blob: eb01145bd5dd0d5f7f9d8ea8d3af77a8d3ff45f3 [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) {
1118 ctxt->valueMax *= 2;
1119 ctxt->valueTab =
1120 (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1121 ctxt->valueMax *
1122 sizeof(ctxt->valueTab[0]));
1123 if (ctxt->valueTab == NULL) {
1124 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1125 return (0);
1126 }
1127 }
1128 ctxt->valueTab[ctxt->valueNr] = value;
1129 ctxt->value = value;
1130 return (ctxt->valueNr++);
1131}
Owen Taylor3473f882001-02-23 17:55:21 +00001132
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001133/**
1134 * xmlXPathPopBoolean:
1135 * @ctxt: an XPath parser context
1136 *
1137 * Pops a boolean from the stack, handling conversion if needed.
1138 * Check error with #xmlXPathCheckError.
1139 *
1140 * Returns the boolean
1141 */
1142int
1143xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1144 xmlXPathObjectPtr obj;
1145 int ret;
1146
1147 obj = valuePop(ctxt);
1148 if (obj == NULL) {
1149 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1150 return(0);
1151 }
William M. Brack08171912003-12-29 02:52:11 +00001152 if (obj->type != XPATH_BOOLEAN)
1153 ret = xmlXPathCastToBoolean(obj);
1154 else
1155 ret = obj->boolval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001156 xmlXPathFreeObject(obj);
1157 return(ret);
1158}
1159
1160/**
1161 * xmlXPathPopNumber:
1162 * @ctxt: an XPath parser context
1163 *
1164 * Pops a number from the stack, handling conversion if needed.
1165 * Check error with #xmlXPathCheckError.
1166 *
1167 * Returns the number
1168 */
1169double
1170xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1171 xmlXPathObjectPtr obj;
1172 double ret;
1173
1174 obj = valuePop(ctxt);
1175 if (obj == NULL) {
1176 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1177 return(0);
1178 }
William M. Brack08171912003-12-29 02:52:11 +00001179 if (obj->type != XPATH_NUMBER)
1180 ret = xmlXPathCastToNumber(obj);
1181 else
1182 ret = obj->floatval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001183 xmlXPathFreeObject(obj);
1184 return(ret);
1185}
1186
1187/**
1188 * xmlXPathPopString:
1189 * @ctxt: an XPath parser context
1190 *
1191 * Pops a string from the stack, handling conversion if needed.
1192 * Check error with #xmlXPathCheckError.
1193 *
1194 * Returns the string
1195 */
1196xmlChar *
1197xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1198 xmlXPathObjectPtr obj;
1199 xmlChar * ret;
1200
1201 obj = valuePop(ctxt);
1202 if (obj == NULL) {
1203 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1204 return(NULL);
1205 }
William M. Brack08171912003-12-29 02:52:11 +00001206 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001207 /* TODO: needs refactoring somewhere else */
1208 if (obj->stringval == ret)
1209 obj->stringval = NULL;
1210 xmlXPathFreeObject(obj);
1211 return(ret);
1212}
1213
1214/**
1215 * xmlXPathPopNodeSet:
1216 * @ctxt: an XPath parser context
1217 *
1218 * Pops a node-set from the stack, handling conversion if needed.
1219 * Check error with #xmlXPathCheckError.
1220 *
1221 * Returns the node-set
1222 */
1223xmlNodeSetPtr
1224xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1225 xmlXPathObjectPtr obj;
1226 xmlNodeSetPtr ret;
1227
1228 if (ctxt->value == NULL) {
1229 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1230 return(NULL);
1231 }
1232 if (!xmlXPathStackIsNodeSet(ctxt)) {
1233 xmlXPathSetTypeError(ctxt);
1234 return(NULL);
1235 }
1236 obj = valuePop(ctxt);
1237 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00001238#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00001239 /* to fix memory leak of not clearing obj->user */
1240 if (obj->boolval && obj->user != NULL)
1241 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00001242#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001243 xmlXPathFreeNodeSetList(obj);
1244 return(ret);
1245}
1246
1247/**
1248 * xmlXPathPopExternal:
1249 * @ctxt: an XPath parser context
1250 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001251 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001252 * Check error with #xmlXPathCheckError.
1253 *
1254 * Returns the object
1255 */
1256void *
1257xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1258 xmlXPathObjectPtr obj;
1259 void * ret;
1260
1261 if (ctxt->value == NULL) {
1262 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1263 return(NULL);
1264 }
1265 if (ctxt->value->type != XPATH_USERS) {
1266 xmlXPathSetTypeError(ctxt);
1267 return(NULL);
1268 }
1269 obj = valuePop(ctxt);
1270 ret = obj->user;
1271 xmlXPathFreeObject(obj);
1272 return(ret);
1273}
1274
Owen Taylor3473f882001-02-23 17:55:21 +00001275/*
1276 * Macros for accessing the content. Those should be used only by the parser,
1277 * and not exported.
1278 *
1279 * Dirty macros, i.e. one need to make assumption on the context to use them
1280 *
1281 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1282 * CUR returns the current xmlChar value, i.e. a 8 bit value
1283 * in ISO-Latin or UTF-8.
1284 * This should be used internally by the parser
1285 * only to compare to ASCII values otherwise it would break when
1286 * running with UTF-8 encoding.
1287 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1288 * to compare on ASCII based substring.
1289 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1290 * strings within the parser.
1291 * CURRENT Returns the current char value, with the full decoding of
1292 * UTF-8 if we are using this mode. It returns an int.
1293 * NEXT Skip to the next character, this does the proper decoding
1294 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1295 * It returns the pointer to the current xmlChar.
1296 */
1297
1298#define CUR (*ctxt->cur)
1299#define SKIP(val) ctxt->cur += (val)
1300#define NXT(val) ctxt->cur[(val)]
1301#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001302#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1303
1304#define COPY_BUF(l,b,i,v) \
1305 if (l == 1) b[i++] = (xmlChar) v; \
1306 else i += xmlCopyChar(l,&b[i],v)
1307
1308#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001309
1310#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001311 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001312
1313#define CURRENT (*ctxt->cur)
1314#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1315
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001316
1317#ifndef DBL_DIG
1318#define DBL_DIG 16
1319#endif
1320#ifndef DBL_EPSILON
1321#define DBL_EPSILON 1E-9
1322#endif
1323
1324#define UPPER_DOUBLE 1E9
1325#define LOWER_DOUBLE 1E-5
1326
1327#define INTEGER_DIGITS DBL_DIG
1328#define FRACTION_DIGITS (DBL_DIG + 1)
1329#define EXPONENT_DIGITS (3 + 2)
1330
1331/**
1332 * xmlXPathFormatNumber:
1333 * @number: number to format
1334 * @buffer: output buffer
1335 * @buffersize: size of output buffer
1336 *
1337 * Convert the number into a string representation.
1338 */
1339static void
1340xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1341{
Daniel Veillardcda96922001-08-21 10:56:31 +00001342 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001343 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001344 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001345 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001346 break;
1347 case -1:
1348 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001349 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001350 break;
1351 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001352 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001353 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001354 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001355 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001356 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001357 } else if (number == ((int) number)) {
1358 char work[30];
1359 char *ptr, *cur;
1360 int res, value = (int) number;
1361
1362 ptr = &buffer[0];
1363 if (value < 0) {
1364 *ptr++ = '-';
1365 value = -value;
1366 }
1367 if (value == 0) {
1368 *ptr++ = '0';
1369 } else {
1370 cur = &work[0];
1371 while (value != 0) {
1372 res = value % 10;
1373 value = value / 10;
1374 *cur++ = '0' + res;
1375 }
1376 cur--;
1377 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1378 *ptr++ = *cur--;
1379 }
1380 }
1381 if (ptr - buffer < buffersize) {
1382 *ptr = 0;
1383 } else if (buffersize > 0) {
1384 ptr--;
1385 *ptr = 0;
1386 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001387 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001388 /* 3 is sign, decimal point, and terminating zero */
1389 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1390 int integer_place, fraction_place;
1391 char *ptr;
1392 char *after_fraction;
1393 double absolute_value;
1394 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001395
Bjorn Reese70a9da52001-04-21 16:57:29 +00001396 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001397
Bjorn Reese70a9da52001-04-21 16:57:29 +00001398 /*
1399 * First choose format - scientific or regular floating point.
1400 * In either case, result is in work, and after_fraction points
1401 * just past the fractional part.
1402 */
1403 if ( ((absolute_value > UPPER_DOUBLE) ||
1404 (absolute_value < LOWER_DOUBLE)) &&
1405 (absolute_value != 0.0) ) {
1406 /* Use scientific notation */
1407 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1408 fraction_place = DBL_DIG - 1;
1409 snprintf(work, sizeof(work),"%*.*e",
1410 integer_place, fraction_place, number);
1411 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001412 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001413 else {
1414 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001415 if (absolute_value > 0.0)
1416 integer_place = 1 + (int)log10(absolute_value);
1417 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001418 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001419 fraction_place = (integer_place > 0)
1420 ? DBL_DIG - integer_place
1421 : DBL_DIG;
1422 size = snprintf(work, sizeof(work), "%0.*f",
1423 fraction_place, number);
1424 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001425 }
1426
Bjorn Reese70a9da52001-04-21 16:57:29 +00001427 /* Remove fractional trailing zeroes */
1428 ptr = after_fraction;
1429 while (*(--ptr) == '0')
1430 ;
1431 if (*ptr != '.')
1432 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001433 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001434
1435 /* Finally copy result back to caller */
1436 size = strlen(work) + 1;
1437 if (size > buffersize) {
1438 work[buffersize - 1] = 0;
1439 size = buffersize;
1440 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001441 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001442 }
1443 break;
1444 }
1445}
1446
Owen Taylor3473f882001-02-23 17:55:21 +00001447
1448/************************************************************************
1449 * *
1450 * Routines to handle NodeSets *
1451 * *
1452 ************************************************************************/
1453
1454/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001455 * xmlXPathOrderDocElems:
1456 * @doc: an input document
1457 *
1458 * Call this routine to speed up XPath computation on static documents.
1459 * This stamps all the element nodes with the document order
1460 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00001461 * field, the value stored is actually - the node number (starting at -1)
1462 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001463 *
William M. Brack08171912003-12-29 02:52:11 +00001464 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001465 * of error.
1466 */
1467long
1468xmlXPathOrderDocElems(xmlDocPtr doc) {
1469 long count = 0;
1470 xmlNodePtr cur;
1471
1472 if (doc == NULL)
1473 return(-1);
1474 cur = doc->children;
1475 while (cur != NULL) {
1476 if (cur->type == XML_ELEMENT_NODE) {
1477 cur->content = (void *) (-(++count));
1478 if (cur->children != NULL) {
1479 cur = cur->children;
1480 continue;
1481 }
1482 }
1483 if (cur->next != NULL) {
1484 cur = cur->next;
1485 continue;
1486 }
1487 do {
1488 cur = cur->parent;
1489 if (cur == NULL)
1490 break;
1491 if (cur == (xmlNodePtr) doc) {
1492 cur = NULL;
1493 break;
1494 }
1495 if (cur->next != NULL) {
1496 cur = cur->next;
1497 break;
1498 }
1499 } while (cur != NULL);
1500 }
1501 return(count);
1502}
1503
1504/**
Owen Taylor3473f882001-02-23 17:55:21 +00001505 * xmlXPathCmpNodes:
1506 * @node1: the first node
1507 * @node2: the second node
1508 *
1509 * Compare two nodes w.r.t document order
1510 *
1511 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00001512 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001513 */
1514int
1515xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1516 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001517 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001518 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001519 xmlNodePtr cur, root;
1520
1521 if ((node1 == NULL) || (node2 == NULL))
1522 return(-2);
1523 /*
1524 * a couple of optimizations which will avoid computations in most cases
1525 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001526 if (node1->type == XML_ATTRIBUTE_NODE) {
1527 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001528 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001529 node1 = node1->parent;
1530 }
1531 if (node2->type == XML_ATTRIBUTE_NODE) {
1532 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001533 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001534 node2 = node2->parent;
1535 }
1536 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001537 if (attr1 == attr2) {
1538 /* not required, but we keep attributes in order */
1539 if (attr1 != 0) {
1540 cur = attrNode2->prev;
1541 while (cur != NULL) {
1542 if (cur == attrNode1)
1543 return (1);
1544 cur = cur->prev;
1545 }
1546 return (-1);
1547 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001548 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001549 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001550 if (attr2 == 1)
1551 return(1);
1552 return(-1);
1553 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001554 if ((node1->type == XML_NAMESPACE_DECL) ||
1555 (node2->type == XML_NAMESPACE_DECL))
1556 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001557 if (node1 == node2->prev)
1558 return(1);
1559 if (node1 == node2->next)
1560 return(-1);
1561
1562 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001563 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001564 */
1565 if ((node1->type == XML_ELEMENT_NODE) &&
1566 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001567 (0 > (long) node1->content) &&
1568 (0 > (long) node2->content) &&
1569 (node1->doc == node2->doc)) {
1570 long l1, l2;
1571
1572 l1 = -((long) node1->content);
1573 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001574 if (l1 < l2)
1575 return(1);
1576 if (l1 > l2)
1577 return(-1);
1578 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001579
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001580 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001581 * compute depth to root
1582 */
1583 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1584 if (cur == node1)
1585 return(1);
1586 depth2++;
1587 }
1588 root = cur;
1589 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1590 if (cur == node2)
1591 return(-1);
1592 depth1++;
1593 }
1594 /*
1595 * Distinct document (or distinct entities :-( ) case.
1596 */
1597 if (root != cur) {
1598 return(-2);
1599 }
1600 /*
1601 * get the nearest common ancestor.
1602 */
1603 while (depth1 > depth2) {
1604 depth1--;
1605 node1 = node1->parent;
1606 }
1607 while (depth2 > depth1) {
1608 depth2--;
1609 node2 = node2->parent;
1610 }
1611 while (node1->parent != node2->parent) {
1612 node1 = node1->parent;
1613 node2 = node2->parent;
1614 /* should not happen but just in case ... */
1615 if ((node1 == NULL) || (node2 == NULL))
1616 return(-2);
1617 }
1618 /*
1619 * Find who's first.
1620 */
Daniel Veillardf49be472004-02-17 11:48:18 +00001621 if (node1 == node2->prev)
1622 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001623 if (node1 == node2->next)
1624 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00001625 /*
1626 * Speedup using document order if availble.
1627 */
1628 if ((node1->type == XML_ELEMENT_NODE) &&
1629 (node2->type == XML_ELEMENT_NODE) &&
1630 (0 > (long) node1->content) &&
1631 (0 > (long) node2->content) &&
1632 (node1->doc == node2->doc)) {
1633 long l1, l2;
1634
1635 l1 = -((long) node1->content);
1636 l2 = -((long) node2->content);
1637 if (l1 < l2)
1638 return(1);
1639 if (l1 > l2)
1640 return(-1);
1641 }
1642
Owen Taylor3473f882001-02-23 17:55:21 +00001643 for (cur = node1->next;cur != NULL;cur = cur->next)
1644 if (cur == node2)
1645 return(1);
1646 return(-1); /* assume there is no sibling list corruption */
1647}
1648
1649/**
1650 * xmlXPathNodeSetSort:
1651 * @set: the node set
1652 *
1653 * Sort the node set in document order
1654 */
1655void
1656xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001657 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001658 xmlNodePtr tmp;
1659
1660 if (set == NULL)
1661 return;
1662
1663 /* Use Shell's sort to sort the node-set */
1664 len = set->nodeNr;
1665 for (incr = len / 2; incr > 0; incr /= 2) {
1666 for (i = incr; i < len; i++) {
1667 j = i - incr;
1668 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001669 if (xmlXPathCmpNodes(set->nodeTab[j],
1670 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001671 tmp = set->nodeTab[j];
1672 set->nodeTab[j] = set->nodeTab[j + incr];
1673 set->nodeTab[j + incr] = tmp;
1674 j -= incr;
1675 } else
1676 break;
1677 }
1678 }
1679 }
1680}
1681
1682#define XML_NODESET_DEFAULT 10
1683/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001684 * xmlXPathNodeSetDupNs:
1685 * @node: the parent node of the namespace XPath node
1686 * @ns: the libxml namespace declaration node.
1687 *
1688 * Namespace node in libxml don't match the XPath semantic. In a node set
1689 * the namespace nodes are duplicated and the next pointer is set to the
1690 * parent node in the XPath semantic.
1691 *
1692 * Returns the newly created object.
1693 */
1694static xmlNodePtr
1695xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1696 xmlNsPtr cur;
1697
1698 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1699 return(NULL);
1700 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1701 return((xmlNodePtr) ns);
1702
1703 /*
1704 * Allocate a new Namespace and fill the fields.
1705 */
1706 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1707 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001708 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001709 return(NULL);
1710 }
1711 memset(cur, 0, sizeof(xmlNs));
1712 cur->type = XML_NAMESPACE_DECL;
1713 if (ns->href != NULL)
1714 cur->href = xmlStrdup(ns->href);
1715 if (ns->prefix != NULL)
1716 cur->prefix = xmlStrdup(ns->prefix);
1717 cur->next = (xmlNsPtr) node;
1718 return((xmlNodePtr) cur);
1719}
1720
1721/**
1722 * xmlXPathNodeSetFreeNs:
1723 * @ns: the XPath namespace node found in a nodeset.
1724 *
William M. Brack08171912003-12-29 02:52:11 +00001725 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001726 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00001727 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001728 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001729void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001730xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1731 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1732 return;
1733
1734 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1735 if (ns->href != NULL)
1736 xmlFree((xmlChar *)ns->href);
1737 if (ns->prefix != NULL)
1738 xmlFree((xmlChar *)ns->prefix);
1739 xmlFree(ns);
1740 }
1741}
1742
1743/**
Owen Taylor3473f882001-02-23 17:55:21 +00001744 * xmlXPathNodeSetCreate:
1745 * @val: an initial xmlNodePtr, or NULL
1746 *
1747 * Create a new xmlNodeSetPtr of type double and of value @val
1748 *
1749 * Returns the newly created object.
1750 */
1751xmlNodeSetPtr
1752xmlXPathNodeSetCreate(xmlNodePtr val) {
1753 xmlNodeSetPtr ret;
1754
1755 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1756 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001757 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001758 return(NULL);
1759 }
1760 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1761 if (val != NULL) {
1762 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1763 sizeof(xmlNodePtr));
1764 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001765 xmlXPathErrMemory(NULL, "creating nodeset\n");
1766 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001767 return(NULL);
1768 }
1769 memset(ret->nodeTab, 0 ,
1770 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1771 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001772 if (val->type == XML_NAMESPACE_DECL) {
1773 xmlNsPtr ns = (xmlNsPtr) val;
1774
1775 ret->nodeTab[ret->nodeNr++] =
1776 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1777 } else
1778 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001779 }
1780 return(ret);
1781}
1782
1783/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001784 * xmlXPathNodeSetContains:
1785 * @cur: the node-set
1786 * @val: the node
1787 *
1788 * checks whether @cur contains @val
1789 *
1790 * Returns true (1) if @cur contains @val, false (0) otherwise
1791 */
1792int
1793xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1794 int i;
1795
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001796 if (val->type == XML_NAMESPACE_DECL) {
1797 for (i = 0; i < cur->nodeNr; i++) {
1798 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1799 xmlNsPtr ns1, ns2;
1800
1801 ns1 = (xmlNsPtr) val;
1802 ns2 = (xmlNsPtr) cur->nodeTab[i];
1803 if (ns1 == ns2)
1804 return(1);
1805 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1806 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1807 return(1);
1808 }
1809 }
1810 } else {
1811 for (i = 0; i < cur->nodeNr; i++) {
1812 if (cur->nodeTab[i] == val)
1813 return(1);
1814 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001815 }
1816 return(0);
1817}
1818
1819/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001820 * xmlXPathNodeSetAddNs:
1821 * @cur: the initial node set
1822 * @node: the hosting node
1823 * @ns: a the namespace node
1824 *
1825 * add a new namespace node to an existing NodeSet
1826 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001827void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001828xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1829 int i;
1830
1831 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1832 (node->type != XML_ELEMENT_NODE))
1833 return;
1834
William M. Brack08171912003-12-29 02:52:11 +00001835 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001836 /*
William M. Brack08171912003-12-29 02:52:11 +00001837 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001838 */
1839 for (i = 0;i < cur->nodeNr;i++) {
1840 if ((cur->nodeTab[i] != NULL) &&
1841 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001842 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001843 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1844 return;
1845 }
1846
1847 /*
1848 * grow the nodeTab if needed
1849 */
1850 if (cur->nodeMax == 0) {
1851 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1852 sizeof(xmlNodePtr));
1853 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001854 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001855 return;
1856 }
1857 memset(cur->nodeTab, 0 ,
1858 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1859 cur->nodeMax = XML_NODESET_DEFAULT;
1860 } else if (cur->nodeNr == cur->nodeMax) {
1861 xmlNodePtr *temp;
1862
1863 cur->nodeMax *= 2;
1864 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1865 sizeof(xmlNodePtr));
1866 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001867 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001868 return;
1869 }
1870 cur->nodeTab = temp;
1871 }
1872 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1873}
1874
1875/**
Owen Taylor3473f882001-02-23 17:55:21 +00001876 * xmlXPathNodeSetAdd:
1877 * @cur: the initial node set
1878 * @val: a new xmlNodePtr
1879 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001880 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001881 */
1882void
1883xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1884 int i;
1885
1886 if (val == NULL) return;
1887
Daniel Veillardef0b4502003-03-24 13:57:34 +00001888#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001889 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1890 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001891#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001892
William M. Brack08171912003-12-29 02:52:11 +00001893 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001894 /*
William M. Brack08171912003-12-29 02:52:11 +00001895 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00001896 */
1897 for (i = 0;i < cur->nodeNr;i++)
1898 if (cur->nodeTab[i] == val) return;
1899
1900 /*
1901 * grow the nodeTab if needed
1902 */
1903 if (cur->nodeMax == 0) {
1904 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1905 sizeof(xmlNodePtr));
1906 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001907 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001908 return;
1909 }
1910 memset(cur->nodeTab, 0 ,
1911 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1912 cur->nodeMax = XML_NODESET_DEFAULT;
1913 } else if (cur->nodeNr == cur->nodeMax) {
1914 xmlNodePtr *temp;
1915
1916 cur->nodeMax *= 2;
1917 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1918 sizeof(xmlNodePtr));
1919 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001920 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001921 return;
1922 }
1923 cur->nodeTab = temp;
1924 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001925 if (val->type == XML_NAMESPACE_DECL) {
1926 xmlNsPtr ns = (xmlNsPtr) val;
1927
1928 cur->nodeTab[cur->nodeNr++] =
1929 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1930 } else
1931 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001932}
1933
1934/**
1935 * xmlXPathNodeSetAddUnique:
1936 * @cur: the initial node set
1937 * @val: a new xmlNodePtr
1938 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001939 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001940 * when we are sure the node is not already in the set.
1941 */
1942void
1943xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1944 if (val == NULL) return;
1945
Daniel Veillardef0b4502003-03-24 13:57:34 +00001946#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001947 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1948 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001949#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001950
William M. Brack08171912003-12-29 02:52:11 +00001951 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001952 /*
1953 * grow the nodeTab if needed
1954 */
1955 if (cur->nodeMax == 0) {
1956 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1957 sizeof(xmlNodePtr));
1958 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001959 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001960 return;
1961 }
1962 memset(cur->nodeTab, 0 ,
1963 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1964 cur->nodeMax = XML_NODESET_DEFAULT;
1965 } else if (cur->nodeNr == cur->nodeMax) {
1966 xmlNodePtr *temp;
1967
1968 cur->nodeMax *= 2;
1969 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1970 sizeof(xmlNodePtr));
1971 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001972 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001973 return;
1974 }
1975 cur->nodeTab = temp;
1976 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001977 if (val->type == XML_NAMESPACE_DECL) {
1978 xmlNsPtr ns = (xmlNsPtr) val;
1979
1980 cur->nodeTab[cur->nodeNr++] =
1981 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1982 } else
1983 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001984}
1985
1986/**
1987 * xmlXPathNodeSetMerge:
1988 * @val1: the first NodeSet or NULL
1989 * @val2: the second NodeSet
1990 *
1991 * Merges two nodesets, all nodes from @val2 are added to @val1
1992 * if @val1 is NULL, a new set is created and copied from @val2
1993 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001994 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001995 */
1996xmlNodeSetPtr
1997xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001998 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001999
2000 if (val2 == NULL) return(val1);
2001 if (val1 == NULL) {
2002 val1 = xmlXPathNodeSetCreate(NULL);
2003 }
2004
William M. Brack08171912003-12-29 02:52:11 +00002005 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002006 initNr = val1->nodeNr;
2007
2008 for (i = 0;i < val2->nodeNr;i++) {
2009 /*
William M. Brack08171912003-12-29 02:52:11 +00002010 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00002011 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002012 skip = 0;
2013 for (j = 0; j < initNr; j++) {
2014 if (val1->nodeTab[j] == val2->nodeTab[i]) {
2015 skip = 1;
2016 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002017 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
2018 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
2019 xmlNsPtr ns1, ns2;
2020 ns1 = (xmlNsPtr) val1->nodeTab[j];
2021 ns2 = (xmlNsPtr) val2->nodeTab[i];
2022 if ((ns1->next == ns2->next) &&
2023 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
2024 skip = 1;
2025 break;
2026 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002027 }
2028 }
2029 if (skip)
2030 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00002031
2032 /*
2033 * grow the nodeTab if needed
2034 */
2035 if (val1->nodeMax == 0) {
2036 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2037 sizeof(xmlNodePtr));
2038 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002039 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002040 return(NULL);
2041 }
2042 memset(val1->nodeTab, 0 ,
2043 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2044 val1->nodeMax = XML_NODESET_DEFAULT;
2045 } else if (val1->nodeNr == val1->nodeMax) {
2046 xmlNodePtr *temp;
2047
2048 val1->nodeMax *= 2;
2049 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2050 sizeof(xmlNodePtr));
2051 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002052 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002053 return(NULL);
2054 }
2055 val1->nodeTab = temp;
2056 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002057 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2058 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2059
2060 val1->nodeTab[val1->nodeNr++] =
2061 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2062 } else
2063 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002064 }
2065
2066 return(val1);
2067}
2068
2069/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002070 * xmlXPathNodeSetMergeUnique:
2071 * @val1: the first NodeSet or NULL
2072 * @val2: the second NodeSet
2073 *
2074 * Merges two nodesets, all nodes from @val2 are added to @val1
2075 * if @val1 is NULL, a new set is created and copied from @val2
2076 *
2077 * Returns @val1 once extended or NULL in case of error.
2078 */
2079static xmlNodeSetPtr
2080xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002081 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002082
2083 if (val2 == NULL) return(val1);
2084 if (val1 == NULL) {
2085 val1 = xmlXPathNodeSetCreate(NULL);
2086 }
2087
William M. Brack08171912003-12-29 02:52:11 +00002088 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002089
2090 for (i = 0;i < val2->nodeNr;i++) {
2091 /*
2092 * grow the nodeTab if needed
2093 */
2094 if (val1->nodeMax == 0) {
2095 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2096 sizeof(xmlNodePtr));
2097 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002098 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002099 return(NULL);
2100 }
2101 memset(val1->nodeTab, 0 ,
2102 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2103 val1->nodeMax = XML_NODESET_DEFAULT;
2104 } else if (val1->nodeNr == val1->nodeMax) {
2105 xmlNodePtr *temp;
2106
2107 val1->nodeMax *= 2;
2108 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2109 sizeof(xmlNodePtr));
2110 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002111 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002112 return(NULL);
2113 }
2114 val1->nodeTab = temp;
2115 }
2116 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2117 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2118
2119 val1->nodeTab[val1->nodeNr++] =
2120 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2121 } else
2122 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2123 }
2124
2125 return(val1);
2126}
2127
2128/**
Owen Taylor3473f882001-02-23 17:55:21 +00002129 * xmlXPathNodeSetDel:
2130 * @cur: the initial node set
2131 * @val: an xmlNodePtr
2132 *
2133 * Removes an xmlNodePtr from an existing NodeSet
2134 */
2135void
2136xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2137 int i;
2138
2139 if (cur == NULL) return;
2140 if (val == NULL) return;
2141
2142 /*
William M. Brack08171912003-12-29 02:52:11 +00002143 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002144 */
2145 for (i = 0;i < cur->nodeNr;i++)
2146 if (cur->nodeTab[i] == val) break;
2147
William M. Brack08171912003-12-29 02:52:11 +00002148 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002149#ifdef DEBUG
2150 xmlGenericError(xmlGenericErrorContext,
2151 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2152 val->name);
2153#endif
2154 return;
2155 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002156 if ((cur->nodeTab[i] != NULL) &&
2157 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2158 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002159 cur->nodeNr--;
2160 for (;i < cur->nodeNr;i++)
2161 cur->nodeTab[i] = cur->nodeTab[i + 1];
2162 cur->nodeTab[cur->nodeNr] = NULL;
2163}
2164
2165/**
2166 * xmlXPathNodeSetRemove:
2167 * @cur: the initial node set
2168 * @val: the index to remove
2169 *
2170 * Removes an entry from an existing NodeSet list.
2171 */
2172void
2173xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2174 if (cur == NULL) return;
2175 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002176 if ((cur->nodeTab[val] != NULL) &&
2177 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2178 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002179 cur->nodeNr--;
2180 for (;val < cur->nodeNr;val++)
2181 cur->nodeTab[val] = cur->nodeTab[val + 1];
2182 cur->nodeTab[cur->nodeNr] = NULL;
2183}
2184
2185/**
2186 * xmlXPathFreeNodeSet:
2187 * @obj: the xmlNodeSetPtr to free
2188 *
2189 * Free the NodeSet compound (not the actual nodes !).
2190 */
2191void
2192xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2193 if (obj == NULL) return;
2194 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002195 int i;
2196
William M. Brack08171912003-12-29 02:52:11 +00002197 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002198 for (i = 0;i < obj->nodeNr;i++)
2199 if ((obj->nodeTab[i] != NULL) &&
2200 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2201 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002202 xmlFree(obj->nodeTab);
2203 }
Owen Taylor3473f882001-02-23 17:55:21 +00002204 xmlFree(obj);
2205}
2206
2207/**
2208 * xmlXPathFreeValueTree:
2209 * @obj: the xmlNodeSetPtr to free
2210 *
2211 * Free the NodeSet compound and the actual tree, this is different
2212 * from xmlXPathFreeNodeSet()
2213 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002214static void
Owen Taylor3473f882001-02-23 17:55:21 +00002215xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2216 int i;
2217
2218 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002219
2220 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002221 for (i = 0;i < obj->nodeNr;i++) {
2222 if (obj->nodeTab[i] != NULL) {
2223 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2224 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2225 } else {
2226 xmlFreeNodeList(obj->nodeTab[i]);
2227 }
2228 }
2229 }
Owen Taylor3473f882001-02-23 17:55:21 +00002230 xmlFree(obj->nodeTab);
2231 }
Owen Taylor3473f882001-02-23 17:55:21 +00002232 xmlFree(obj);
2233}
2234
2235#if defined(DEBUG) || defined(DEBUG_STEP)
2236/**
2237 * xmlGenericErrorContextNodeSet:
2238 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002239 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002240 *
2241 * Quick display of a NodeSet
2242 */
2243void
2244xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2245 int i;
2246
2247 if (output == NULL) output = xmlGenericErrorContext;
2248 if (obj == NULL) {
2249 fprintf(output, "NodeSet == NULL !\n");
2250 return;
2251 }
2252 if (obj->nodeNr == 0) {
2253 fprintf(output, "NodeSet is empty\n");
2254 return;
2255 }
2256 if (obj->nodeTab == NULL) {
2257 fprintf(output, " nodeTab == NULL !\n");
2258 return;
2259 }
2260 for (i = 0; i < obj->nodeNr; i++) {
2261 if (obj->nodeTab[i] == NULL) {
2262 fprintf(output, " NULL !\n");
2263 return;
2264 }
2265 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2266 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2267 fprintf(output, " /");
2268 else if (obj->nodeTab[i]->name == NULL)
2269 fprintf(output, " noname!");
2270 else fprintf(output, " %s", obj->nodeTab[i]->name);
2271 }
2272 fprintf(output, "\n");
2273}
2274#endif
2275
2276/**
2277 * xmlXPathNewNodeSet:
2278 * @val: the NodePtr value
2279 *
2280 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2281 * it with the single Node @val
2282 *
2283 * Returns the newly created object.
2284 */
2285xmlXPathObjectPtr
2286xmlXPathNewNodeSet(xmlNodePtr val) {
2287 xmlXPathObjectPtr ret;
2288
2289 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2290 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002291 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002292 return(NULL);
2293 }
2294 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2295 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002296 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002297 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002298 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002299 return(ret);
2300}
2301
2302/**
2303 * xmlXPathNewValueTree:
2304 * @val: the NodePtr value
2305 *
2306 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2307 * it with the tree root @val
2308 *
2309 * Returns the newly created object.
2310 */
2311xmlXPathObjectPtr
2312xmlXPathNewValueTree(xmlNodePtr val) {
2313 xmlXPathObjectPtr ret;
2314
2315 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2316 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002317 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002318 return(NULL);
2319 }
2320 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2321 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002322 ret->boolval = 1;
2323 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002324 ret->nodesetval = xmlXPathNodeSetCreate(val);
2325 return(ret);
2326}
2327
2328/**
2329 * xmlXPathNewNodeSetList:
2330 * @val: an existing NodeSet
2331 *
2332 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2333 * it with the Nodeset @val
2334 *
2335 * Returns the newly created object.
2336 */
2337xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002338xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2339{
Owen Taylor3473f882001-02-23 17:55:21 +00002340 xmlXPathObjectPtr ret;
2341 int i;
2342
2343 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002344 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002345 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002346 ret = xmlXPathNewNodeSet(NULL);
2347 else {
2348 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2349 for (i = 1; i < val->nodeNr; ++i)
2350 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2351 }
Owen Taylor3473f882001-02-23 17:55:21 +00002352
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002353 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002354}
2355
2356/**
2357 * xmlXPathWrapNodeSet:
2358 * @val: the NodePtr value
2359 *
2360 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2361 *
2362 * Returns the newly created object.
2363 */
2364xmlXPathObjectPtr
2365xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2366 xmlXPathObjectPtr ret;
2367
2368 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2369 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002370 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002371 return(NULL);
2372 }
2373 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2374 ret->type = XPATH_NODESET;
2375 ret->nodesetval = val;
2376 return(ret);
2377}
2378
2379/**
2380 * xmlXPathFreeNodeSetList:
2381 * @obj: an existing NodeSetList object
2382 *
2383 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2384 * the list contrary to xmlXPathFreeObject().
2385 */
2386void
2387xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2388 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002389 xmlFree(obj);
2390}
2391
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002392/**
2393 * xmlXPathDifference:
2394 * @nodes1: a node-set
2395 * @nodes2: a node-set
2396 *
2397 * Implements the EXSLT - Sets difference() function:
2398 * node-set set:difference (node-set, node-set)
2399 *
2400 * Returns the difference between the two node sets, or nodes1 if
2401 * nodes2 is empty
2402 */
2403xmlNodeSetPtr
2404xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2405 xmlNodeSetPtr ret;
2406 int i, l1;
2407 xmlNodePtr cur;
2408
2409 if (xmlXPathNodeSetIsEmpty(nodes2))
2410 return(nodes1);
2411
2412 ret = xmlXPathNodeSetCreate(NULL);
2413 if (xmlXPathNodeSetIsEmpty(nodes1))
2414 return(ret);
2415
2416 l1 = xmlXPathNodeSetGetLength(nodes1);
2417
2418 for (i = 0; i < l1; i++) {
2419 cur = xmlXPathNodeSetItem(nodes1, i);
2420 if (!xmlXPathNodeSetContains(nodes2, cur))
2421 xmlXPathNodeSetAddUnique(ret, cur);
2422 }
2423 return(ret);
2424}
2425
2426/**
2427 * xmlXPathIntersection:
2428 * @nodes1: a node-set
2429 * @nodes2: a node-set
2430 *
2431 * Implements the EXSLT - Sets intersection() function:
2432 * node-set set:intersection (node-set, node-set)
2433 *
2434 * Returns a node set comprising the nodes that are within both the
2435 * node sets passed as arguments
2436 */
2437xmlNodeSetPtr
2438xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2439 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2440 int i, l1;
2441 xmlNodePtr cur;
2442
2443 if (xmlXPathNodeSetIsEmpty(nodes1))
2444 return(ret);
2445 if (xmlXPathNodeSetIsEmpty(nodes2))
2446 return(ret);
2447
2448 l1 = xmlXPathNodeSetGetLength(nodes1);
2449
2450 for (i = 0; i < l1; i++) {
2451 cur = xmlXPathNodeSetItem(nodes1, i);
2452 if (xmlXPathNodeSetContains(nodes2, cur))
2453 xmlXPathNodeSetAddUnique(ret, cur);
2454 }
2455 return(ret);
2456}
2457
2458/**
2459 * xmlXPathDistinctSorted:
2460 * @nodes: a node-set, sorted by document order
2461 *
2462 * Implements the EXSLT - Sets distinct() function:
2463 * node-set set:distinct (node-set)
2464 *
2465 * Returns a subset of the nodes contained in @nodes, or @nodes if
2466 * it is empty
2467 */
2468xmlNodeSetPtr
2469xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2470 xmlNodeSetPtr ret;
2471 xmlHashTablePtr hash;
2472 int i, l;
2473 xmlChar * strval;
2474 xmlNodePtr cur;
2475
2476 if (xmlXPathNodeSetIsEmpty(nodes))
2477 return(nodes);
2478
2479 ret = xmlXPathNodeSetCreate(NULL);
2480 l = xmlXPathNodeSetGetLength(nodes);
2481 hash = xmlHashCreate (l);
2482 for (i = 0; i < l; i++) {
2483 cur = xmlXPathNodeSetItem(nodes, i);
2484 strval = xmlXPathCastNodeToString(cur);
2485 if (xmlHashLookup(hash, strval) == NULL) {
2486 xmlHashAddEntry(hash, strval, strval);
2487 xmlXPathNodeSetAddUnique(ret, cur);
2488 } else {
2489 xmlFree(strval);
2490 }
2491 }
2492 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2493 return(ret);
2494}
2495
2496/**
2497 * xmlXPathDistinct:
2498 * @nodes: a node-set
2499 *
2500 * Implements the EXSLT - Sets distinct() function:
2501 * node-set set:distinct (node-set)
2502 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2503 * is called with the sorted node-set
2504 *
2505 * Returns a subset of the nodes contained in @nodes, or @nodes if
2506 * it is empty
2507 */
2508xmlNodeSetPtr
2509xmlXPathDistinct (xmlNodeSetPtr nodes) {
2510 if (xmlXPathNodeSetIsEmpty(nodes))
2511 return(nodes);
2512
2513 xmlXPathNodeSetSort(nodes);
2514 return(xmlXPathDistinctSorted(nodes));
2515}
2516
2517/**
2518 * xmlXPathHasSameNodes:
2519 * @nodes1: a node-set
2520 * @nodes2: a node-set
2521 *
2522 * Implements the EXSLT - Sets has-same-nodes function:
2523 * boolean set:has-same-node(node-set, node-set)
2524 *
2525 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2526 * otherwise
2527 */
2528int
2529xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2530 int i, l;
2531 xmlNodePtr cur;
2532
2533 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2534 xmlXPathNodeSetIsEmpty(nodes2))
2535 return(0);
2536
2537 l = xmlXPathNodeSetGetLength(nodes1);
2538 for (i = 0; i < l; i++) {
2539 cur = xmlXPathNodeSetItem(nodes1, i);
2540 if (xmlXPathNodeSetContains(nodes2, cur))
2541 return(1);
2542 }
2543 return(0);
2544}
2545
2546/**
2547 * xmlXPathNodeLeadingSorted:
2548 * @nodes: a node-set, sorted by document order
2549 * @node: a node
2550 *
2551 * Implements the EXSLT - Sets leading() function:
2552 * node-set set:leading (node-set, node-set)
2553 *
2554 * Returns the nodes in @nodes that precede @node in document order,
2555 * @nodes if @node is NULL or an empty node-set if @nodes
2556 * doesn't contain @node
2557 */
2558xmlNodeSetPtr
2559xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2560 int i, l;
2561 xmlNodePtr cur;
2562 xmlNodeSetPtr ret;
2563
2564 if (node == NULL)
2565 return(nodes);
2566
2567 ret = xmlXPathNodeSetCreate(NULL);
2568 if (xmlXPathNodeSetIsEmpty(nodes) ||
2569 (!xmlXPathNodeSetContains(nodes, node)))
2570 return(ret);
2571
2572 l = xmlXPathNodeSetGetLength(nodes);
2573 for (i = 0; i < l; i++) {
2574 cur = xmlXPathNodeSetItem(nodes, i);
2575 if (cur == node)
2576 break;
2577 xmlXPathNodeSetAddUnique(ret, cur);
2578 }
2579 return(ret);
2580}
2581
2582/**
2583 * xmlXPathNodeLeading:
2584 * @nodes: a node-set
2585 * @node: a node
2586 *
2587 * Implements the EXSLT - Sets leading() function:
2588 * node-set set:leading (node-set, node-set)
2589 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2590 * is called.
2591 *
2592 * Returns the nodes in @nodes that precede @node in document order,
2593 * @nodes if @node is NULL or an empty node-set if @nodes
2594 * doesn't contain @node
2595 */
2596xmlNodeSetPtr
2597xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2598 xmlXPathNodeSetSort(nodes);
2599 return(xmlXPathNodeLeadingSorted(nodes, node));
2600}
2601
2602/**
2603 * xmlXPathLeadingSorted:
2604 * @nodes1: a node-set, sorted by document order
2605 * @nodes2: a node-set, sorted by document order
2606 *
2607 * Implements the EXSLT - Sets leading() function:
2608 * node-set set:leading (node-set, node-set)
2609 *
2610 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2611 * in document order, @nodes1 if @nodes2 is NULL or empty or
2612 * an empty node-set if @nodes1 doesn't contain @nodes2
2613 */
2614xmlNodeSetPtr
2615xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2616 if (xmlXPathNodeSetIsEmpty(nodes2))
2617 return(nodes1);
2618 return(xmlXPathNodeLeadingSorted(nodes1,
2619 xmlXPathNodeSetItem(nodes2, 1)));
2620}
2621
2622/**
2623 * xmlXPathLeading:
2624 * @nodes1: a node-set
2625 * @nodes2: a node-set
2626 *
2627 * Implements the EXSLT - Sets leading() function:
2628 * node-set set:leading (node-set, node-set)
2629 * @nodes1 and @nodes2 are sorted by document order, then
2630 * #exslSetsLeadingSorted is called.
2631 *
2632 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2633 * in document order, @nodes1 if @nodes2 is NULL or empty or
2634 * an empty node-set if @nodes1 doesn't contain @nodes2
2635 */
2636xmlNodeSetPtr
2637xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2638 if (xmlXPathNodeSetIsEmpty(nodes2))
2639 return(nodes1);
2640 if (xmlXPathNodeSetIsEmpty(nodes1))
2641 return(xmlXPathNodeSetCreate(NULL));
2642 xmlXPathNodeSetSort(nodes1);
2643 xmlXPathNodeSetSort(nodes2);
2644 return(xmlXPathNodeLeadingSorted(nodes1,
2645 xmlXPathNodeSetItem(nodes2, 1)));
2646}
2647
2648/**
2649 * xmlXPathNodeTrailingSorted:
2650 * @nodes: a node-set, sorted by document order
2651 * @node: a node
2652 *
2653 * Implements the EXSLT - Sets trailing() function:
2654 * node-set set:trailing (node-set, node-set)
2655 *
2656 * Returns the nodes in @nodes that follow @node in document order,
2657 * @nodes if @node is NULL or an empty node-set if @nodes
2658 * doesn't contain @node
2659 */
2660xmlNodeSetPtr
2661xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2662 int i, l;
2663 xmlNodePtr cur;
2664 xmlNodeSetPtr ret;
2665
2666 if (node == NULL)
2667 return(nodes);
2668
2669 ret = xmlXPathNodeSetCreate(NULL);
2670 if (xmlXPathNodeSetIsEmpty(nodes) ||
2671 (!xmlXPathNodeSetContains(nodes, node)))
2672 return(ret);
2673
2674 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002675 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002676 cur = xmlXPathNodeSetItem(nodes, i);
2677 if (cur == node)
2678 break;
2679 xmlXPathNodeSetAddUnique(ret, cur);
2680 }
2681 return(ret);
2682}
2683
2684/**
2685 * xmlXPathNodeTrailing:
2686 * @nodes: a node-set
2687 * @node: a node
2688 *
2689 * Implements the EXSLT - Sets trailing() function:
2690 * node-set set:trailing (node-set, node-set)
2691 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2692 * is called.
2693 *
2694 * Returns the nodes in @nodes that follow @node in document order,
2695 * @nodes if @node is NULL or an empty node-set if @nodes
2696 * doesn't contain @node
2697 */
2698xmlNodeSetPtr
2699xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2700 xmlXPathNodeSetSort(nodes);
2701 return(xmlXPathNodeTrailingSorted(nodes, node));
2702}
2703
2704/**
2705 * xmlXPathTrailingSorted:
2706 * @nodes1: a node-set, sorted by document order
2707 * @nodes2: a node-set, sorted by document order
2708 *
2709 * Implements the EXSLT - Sets trailing() function:
2710 * node-set set:trailing (node-set, node-set)
2711 *
2712 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2713 * in document order, @nodes1 if @nodes2 is NULL or empty or
2714 * an empty node-set if @nodes1 doesn't contain @nodes2
2715 */
2716xmlNodeSetPtr
2717xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2718 if (xmlXPathNodeSetIsEmpty(nodes2))
2719 return(nodes1);
2720 return(xmlXPathNodeTrailingSorted(nodes1,
2721 xmlXPathNodeSetItem(nodes2, 0)));
2722}
2723
2724/**
2725 * xmlXPathTrailing:
2726 * @nodes1: a node-set
2727 * @nodes2: a node-set
2728 *
2729 * Implements the EXSLT - Sets trailing() function:
2730 * node-set set:trailing (node-set, node-set)
2731 * @nodes1 and @nodes2 are sorted by document order, then
2732 * #xmlXPathTrailingSorted is called.
2733 *
2734 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2735 * in document order, @nodes1 if @nodes2 is NULL or empty or
2736 * an empty node-set if @nodes1 doesn't contain @nodes2
2737 */
2738xmlNodeSetPtr
2739xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2740 if (xmlXPathNodeSetIsEmpty(nodes2))
2741 return(nodes1);
2742 if (xmlXPathNodeSetIsEmpty(nodes1))
2743 return(xmlXPathNodeSetCreate(NULL));
2744 xmlXPathNodeSetSort(nodes1);
2745 xmlXPathNodeSetSort(nodes2);
2746 return(xmlXPathNodeTrailingSorted(nodes1,
2747 xmlXPathNodeSetItem(nodes2, 0)));
2748}
2749
Owen Taylor3473f882001-02-23 17:55:21 +00002750/************************************************************************
2751 * *
2752 * Routines to handle extra functions *
2753 * *
2754 ************************************************************************/
2755
2756/**
2757 * xmlXPathRegisterFunc:
2758 * @ctxt: the XPath context
2759 * @name: the function name
2760 * @f: the function implementation or NULL
2761 *
2762 * Register a new function. If @f is NULL it unregisters the function
2763 *
2764 * Returns 0 in case of success, -1 in case of error
2765 */
2766int
2767xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2768 xmlXPathFunction f) {
2769 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2770}
2771
2772/**
2773 * xmlXPathRegisterFuncNS:
2774 * @ctxt: the XPath context
2775 * @name: the function name
2776 * @ns_uri: the function namespace URI
2777 * @f: the function implementation or NULL
2778 *
2779 * Register a new function. If @f is NULL it unregisters the function
2780 *
2781 * Returns 0 in case of success, -1 in case of error
2782 */
2783int
2784xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2785 const xmlChar *ns_uri, xmlXPathFunction f) {
2786 if (ctxt == NULL)
2787 return(-1);
2788 if (name == NULL)
2789 return(-1);
2790
2791 if (ctxt->funcHash == NULL)
2792 ctxt->funcHash = xmlHashCreate(0);
2793 if (ctxt->funcHash == NULL)
2794 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002795 if (f == NULL)
2796 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
Owen Taylor3473f882001-02-23 17:55:21 +00002797 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2798}
2799
2800/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002801 * xmlXPathRegisterFuncLookup:
2802 * @ctxt: the XPath context
2803 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002804 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002805 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002806 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002807 */
2808void
2809xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2810 xmlXPathFuncLookupFunc f,
2811 void *funcCtxt) {
2812 if (ctxt == NULL)
2813 return;
2814 ctxt->funcLookupFunc = (void *) f;
2815 ctxt->funcLookupData = funcCtxt;
2816}
2817
2818/**
Owen Taylor3473f882001-02-23 17:55:21 +00002819 * xmlXPathFunctionLookup:
2820 * @ctxt: the XPath context
2821 * @name: the function name
2822 *
2823 * Search in the Function array of the context for the given
2824 * function.
2825 *
2826 * Returns the xmlXPathFunction or NULL if not found
2827 */
2828xmlXPathFunction
2829xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002830 if (ctxt == NULL)
2831 return (NULL);
2832
2833 if (ctxt->funcLookupFunc != NULL) {
2834 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002835 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002836
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002837 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002838 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002839 if (ret != NULL)
2840 return(ret);
2841 }
Owen Taylor3473f882001-02-23 17:55:21 +00002842 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2843}
2844
2845/**
2846 * xmlXPathFunctionLookupNS:
2847 * @ctxt: the XPath context
2848 * @name: the function name
2849 * @ns_uri: the function namespace URI
2850 *
2851 * Search in the Function array of the context for the given
2852 * function.
2853 *
2854 * Returns the xmlXPathFunction or NULL if not found
2855 */
2856xmlXPathFunction
2857xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2858 const xmlChar *ns_uri) {
2859 if (ctxt == NULL)
2860 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002861 if (name == NULL)
2862 return(NULL);
2863
Thomas Broyerba4ad322001-07-26 16:55:21 +00002864 if (ctxt->funcLookupFunc != NULL) {
2865 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002866 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002867
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002868 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002869 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002870 if (ret != NULL)
2871 return(ret);
2872 }
2873
2874 if (ctxt->funcHash == NULL)
2875 return(NULL);
2876
Owen Taylor3473f882001-02-23 17:55:21 +00002877 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2878}
2879
2880/**
2881 * xmlXPathRegisteredFuncsCleanup:
2882 * @ctxt: the XPath context
2883 *
2884 * Cleanup the XPath context data associated to registered functions
2885 */
2886void
2887xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2888 if (ctxt == NULL)
2889 return;
2890
2891 xmlHashFree(ctxt->funcHash, NULL);
2892 ctxt->funcHash = NULL;
2893}
2894
2895/************************************************************************
2896 * *
William M. Brack08171912003-12-29 02:52:11 +00002897 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00002898 * *
2899 ************************************************************************/
2900
2901/**
2902 * xmlXPathRegisterVariable:
2903 * @ctxt: the XPath context
2904 * @name: the variable name
2905 * @value: the variable value or NULL
2906 *
2907 * Register a new variable value. If @value is NULL it unregisters
2908 * the variable
2909 *
2910 * Returns 0 in case of success, -1 in case of error
2911 */
2912int
2913xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2914 xmlXPathObjectPtr value) {
2915 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2916}
2917
2918/**
2919 * xmlXPathRegisterVariableNS:
2920 * @ctxt: the XPath context
2921 * @name: the variable name
2922 * @ns_uri: the variable namespace URI
2923 * @value: the variable value or NULL
2924 *
2925 * Register a new variable value. If @value is NULL it unregisters
2926 * the variable
2927 *
2928 * Returns 0 in case of success, -1 in case of error
2929 */
2930int
2931xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2932 const xmlChar *ns_uri,
2933 xmlXPathObjectPtr value) {
2934 if (ctxt == NULL)
2935 return(-1);
2936 if (name == NULL)
2937 return(-1);
2938
2939 if (ctxt->varHash == NULL)
2940 ctxt->varHash = xmlHashCreate(0);
2941 if (ctxt->varHash == NULL)
2942 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002943 if (value == NULL)
2944 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2945 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002946 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2947 (void *) value,
2948 (xmlHashDeallocator)xmlXPathFreeObject));
2949}
2950
2951/**
2952 * xmlXPathRegisterVariableLookup:
2953 * @ctxt: the XPath context
2954 * @f: the lookup function
2955 * @data: the lookup data
2956 *
2957 * register an external mechanism to do variable lookup
2958 */
2959void
2960xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2961 xmlXPathVariableLookupFunc f, void *data) {
2962 if (ctxt == NULL)
2963 return;
2964 ctxt->varLookupFunc = (void *) f;
2965 ctxt->varLookupData = data;
2966}
2967
2968/**
2969 * xmlXPathVariableLookup:
2970 * @ctxt: the XPath context
2971 * @name: the variable name
2972 *
2973 * Search in the Variable array of the context for the given
2974 * variable value.
2975 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002976 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002977 */
2978xmlXPathObjectPtr
2979xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2980 if (ctxt == NULL)
2981 return(NULL);
2982
2983 if (ctxt->varLookupFunc != NULL) {
2984 xmlXPathObjectPtr ret;
2985
2986 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2987 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002988 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002989 }
2990 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2991}
2992
2993/**
2994 * xmlXPathVariableLookupNS:
2995 * @ctxt: the XPath context
2996 * @name: the variable name
2997 * @ns_uri: the variable namespace URI
2998 *
2999 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00003000 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00003001 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003002 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003003 */
3004xmlXPathObjectPtr
3005xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3006 const xmlChar *ns_uri) {
3007 if (ctxt == NULL)
3008 return(NULL);
3009
3010 if (ctxt->varLookupFunc != NULL) {
3011 xmlXPathObjectPtr ret;
3012
3013 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3014 (ctxt->varLookupData, name, ns_uri);
3015 if (ret != NULL) return(ret);
3016 }
3017
3018 if (ctxt->varHash == NULL)
3019 return(NULL);
3020 if (name == NULL)
3021 return(NULL);
3022
Daniel Veillard8c357d52001-07-03 23:43:33 +00003023 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3024 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00003025}
3026
3027/**
3028 * xmlXPathRegisteredVariablesCleanup:
3029 * @ctxt: the XPath context
3030 *
3031 * Cleanup the XPath context data associated to registered variables
3032 */
3033void
3034xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3035 if (ctxt == NULL)
3036 return;
3037
Daniel Veillard76d66f42001-05-16 21:05:17 +00003038 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00003039 ctxt->varHash = NULL;
3040}
3041
3042/**
3043 * xmlXPathRegisterNs:
3044 * @ctxt: the XPath context
3045 * @prefix: the namespace prefix
3046 * @ns_uri: the namespace name
3047 *
3048 * Register a new namespace. If @ns_uri is NULL it unregisters
3049 * the namespace
3050 *
3051 * Returns 0 in case of success, -1 in case of error
3052 */
3053int
3054xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3055 const xmlChar *ns_uri) {
3056 if (ctxt == NULL)
3057 return(-1);
3058 if (prefix == NULL)
3059 return(-1);
3060
3061 if (ctxt->nsHash == NULL)
3062 ctxt->nsHash = xmlHashCreate(10);
3063 if (ctxt->nsHash == NULL)
3064 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003065 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003066 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003067 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003068 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003069 (xmlHashDeallocator)xmlFree));
3070}
3071
3072/**
3073 * xmlXPathNsLookup:
3074 * @ctxt: the XPath context
3075 * @prefix: the namespace prefix value
3076 *
3077 * Search in the namespace declaration array of the context for the given
3078 * namespace name associated to the given prefix
3079 *
3080 * Returns the value or NULL if not found
3081 */
3082const xmlChar *
3083xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3084 if (ctxt == NULL)
3085 return(NULL);
3086 if (prefix == NULL)
3087 return(NULL);
3088
3089#ifdef XML_XML_NAMESPACE
3090 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3091 return(XML_XML_NAMESPACE);
3092#endif
3093
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003094 if (ctxt->namespaces != NULL) {
3095 int i;
3096
3097 for (i = 0;i < ctxt->nsNr;i++) {
3098 if ((ctxt->namespaces[i] != NULL) &&
3099 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3100 return(ctxt->namespaces[i]->href);
3101 }
3102 }
Owen Taylor3473f882001-02-23 17:55:21 +00003103
3104 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3105}
3106
3107/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003108 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003109 * @ctxt: the XPath context
3110 *
3111 * Cleanup the XPath context data associated to registered variables
3112 */
3113void
3114xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3115 if (ctxt == NULL)
3116 return;
3117
Daniel Veillard42766c02002-08-22 20:52:17 +00003118 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003119 ctxt->nsHash = NULL;
3120}
3121
3122/************************************************************************
3123 * *
3124 * Routines to handle Values *
3125 * *
3126 ************************************************************************/
3127
William M. Brack08171912003-12-29 02:52:11 +00003128/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003129
3130/**
3131 * xmlXPathNewFloat:
3132 * @val: the double value
3133 *
3134 * Create a new xmlXPathObjectPtr of type double and of value @val
3135 *
3136 * Returns the newly created object.
3137 */
3138xmlXPathObjectPtr
3139xmlXPathNewFloat(double val) {
3140 xmlXPathObjectPtr ret;
3141
3142 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3143 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003144 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003145 return(NULL);
3146 }
3147 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3148 ret->type = XPATH_NUMBER;
3149 ret->floatval = val;
3150 return(ret);
3151}
3152
3153/**
3154 * xmlXPathNewBoolean:
3155 * @val: the boolean value
3156 *
3157 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3158 *
3159 * Returns the newly created object.
3160 */
3161xmlXPathObjectPtr
3162xmlXPathNewBoolean(int val) {
3163 xmlXPathObjectPtr ret;
3164
3165 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3166 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003167 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003168 return(NULL);
3169 }
3170 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3171 ret->type = XPATH_BOOLEAN;
3172 ret->boolval = (val != 0);
3173 return(ret);
3174}
3175
3176/**
3177 * xmlXPathNewString:
3178 * @val: the xmlChar * value
3179 *
3180 * Create a new xmlXPathObjectPtr of type string and of value @val
3181 *
3182 * Returns the newly created object.
3183 */
3184xmlXPathObjectPtr
3185xmlXPathNewString(const xmlChar *val) {
3186 xmlXPathObjectPtr ret;
3187
3188 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3189 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003190 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003191 return(NULL);
3192 }
3193 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3194 ret->type = XPATH_STRING;
3195 if (val != NULL)
3196 ret->stringval = xmlStrdup(val);
3197 else
3198 ret->stringval = xmlStrdup((const xmlChar *)"");
3199 return(ret);
3200}
3201
3202/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003203 * xmlXPathWrapString:
3204 * @val: the xmlChar * value
3205 *
3206 * Wraps the @val string into an XPath object.
3207 *
3208 * Returns the newly created object.
3209 */
3210xmlXPathObjectPtr
3211xmlXPathWrapString (xmlChar *val) {
3212 xmlXPathObjectPtr ret;
3213
3214 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3215 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003216 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003217 return(NULL);
3218 }
3219 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3220 ret->type = XPATH_STRING;
3221 ret->stringval = val;
3222 return(ret);
3223}
3224
3225/**
Owen Taylor3473f882001-02-23 17:55:21 +00003226 * xmlXPathNewCString:
3227 * @val: the char * value
3228 *
3229 * Create a new xmlXPathObjectPtr of type string and of value @val
3230 *
3231 * Returns the newly created object.
3232 */
3233xmlXPathObjectPtr
3234xmlXPathNewCString(const char *val) {
3235 xmlXPathObjectPtr ret;
3236
3237 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3238 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003239 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003240 return(NULL);
3241 }
3242 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3243 ret->type = XPATH_STRING;
3244 ret->stringval = xmlStrdup(BAD_CAST val);
3245 return(ret);
3246}
3247
3248/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003249 * xmlXPathWrapCString:
3250 * @val: the char * value
3251 *
3252 * Wraps a string into an XPath object.
3253 *
3254 * Returns the newly created object.
3255 */
3256xmlXPathObjectPtr
3257xmlXPathWrapCString (char * val) {
3258 return(xmlXPathWrapString((xmlChar *)(val)));
3259}
3260
3261/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003262 * xmlXPathWrapExternal:
3263 * @val: the user data
3264 *
3265 * Wraps the @val data into an XPath object.
3266 *
3267 * Returns the newly created object.
3268 */
3269xmlXPathObjectPtr
3270xmlXPathWrapExternal (void *val) {
3271 xmlXPathObjectPtr ret;
3272
3273 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3274 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003275 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003276 return(NULL);
3277 }
3278 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3279 ret->type = XPATH_USERS;
3280 ret->user = val;
3281 return(ret);
3282}
3283
3284/**
Owen Taylor3473f882001-02-23 17:55:21 +00003285 * xmlXPathObjectCopy:
3286 * @val: the original object
3287 *
3288 * allocate a new copy of a given object
3289 *
3290 * Returns the newly created object.
3291 */
3292xmlXPathObjectPtr
3293xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3294 xmlXPathObjectPtr ret;
3295
3296 if (val == NULL)
3297 return(NULL);
3298
3299 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3300 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003301 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003302 return(NULL);
3303 }
3304 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3305 switch (val->type) {
3306 case XPATH_BOOLEAN:
3307 case XPATH_NUMBER:
3308 case XPATH_POINT:
3309 case XPATH_RANGE:
3310 break;
3311 case XPATH_STRING:
3312 ret->stringval = xmlStrdup(val->stringval);
3313 break;
3314 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00003315#if 0
3316/*
3317 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
3318 this previous handling is no longer correct, and can cause some serious
3319 problems (ref. bug 145547)
3320*/
Owen Taylor3473f882001-02-23 17:55:21 +00003321 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003322 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003323 xmlNodePtr cur, tmp;
3324 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003325
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003326 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003327 top = xmlNewDoc(NULL);
3328 top->name = (char *)
3329 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003330 ret->user = top;
3331 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003332 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003333 cur = val->nodesetval->nodeTab[0]->children;
3334 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003335 tmp = xmlDocCopyNode(cur, top, 1);
3336 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003337 cur = cur->next;
3338 }
3339 }
William M. Bracke9449c52004-07-11 14:41:20 +00003340
Daniel Veillard9adc0462003-03-24 18:39:54 +00003341 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003342 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003343 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003344 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003345 break;
William M. Bracke9449c52004-07-11 14:41:20 +00003346#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003347 case XPATH_NODESET:
3348 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003349 /* Do not deallocate the copied tree value */
3350 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003351 break;
3352 case XPATH_LOCATIONSET:
3353#ifdef LIBXML_XPTR_ENABLED
3354 {
3355 xmlLocationSetPtr loc = val->user;
3356 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3357 break;
3358 }
3359#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003360 case XPATH_USERS:
3361 ret->user = val->user;
3362 break;
3363 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003364 xmlGenericError(xmlGenericErrorContext,
3365 "xmlXPathObjectCopy: unsupported type %d\n",
3366 val->type);
3367 break;
3368 }
3369 return(ret);
3370}
3371
3372/**
3373 * xmlXPathFreeObject:
3374 * @obj: the object to free
3375 *
3376 * Free up an xmlXPathObjectPtr object.
3377 */
3378void
3379xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3380 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003381 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003382 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00003383#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003384 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003385 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003386 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003387 } else
3388#endif
3389 if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003390 xmlXPathFreeValueTree(obj->nodesetval);
3391 } else {
3392 if (obj->nodesetval != NULL)
3393 xmlXPathFreeNodeSet(obj->nodesetval);
3394 }
Owen Taylor3473f882001-02-23 17:55:21 +00003395#ifdef LIBXML_XPTR_ENABLED
3396 } else if (obj->type == XPATH_LOCATIONSET) {
3397 if (obj->user != NULL)
3398 xmlXPtrFreeLocationSet(obj->user);
3399#endif
3400 } else if (obj->type == XPATH_STRING) {
3401 if (obj->stringval != NULL)
3402 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003403 }
3404
Owen Taylor3473f882001-02-23 17:55:21 +00003405 xmlFree(obj);
3406}
3407
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003408
3409/************************************************************************
3410 * *
3411 * Type Casting Routines *
3412 * *
3413 ************************************************************************/
3414
3415/**
3416 * xmlXPathCastBooleanToString:
3417 * @val: a boolean
3418 *
3419 * Converts a boolean to its string value.
3420 *
3421 * Returns a newly allocated string.
3422 */
3423xmlChar *
3424xmlXPathCastBooleanToString (int val) {
3425 xmlChar *ret;
3426 if (val)
3427 ret = xmlStrdup((const xmlChar *) "true");
3428 else
3429 ret = xmlStrdup((const xmlChar *) "false");
3430 return(ret);
3431}
3432
3433/**
3434 * xmlXPathCastNumberToString:
3435 * @val: a number
3436 *
3437 * Converts a number to its string value.
3438 *
3439 * Returns a newly allocated string.
3440 */
3441xmlChar *
3442xmlXPathCastNumberToString (double val) {
3443 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003444 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003445 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003446 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003447 break;
3448 case -1:
3449 ret = xmlStrdup((const xmlChar *) "-Infinity");
3450 break;
3451 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003452 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003453 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003454 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3455 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003456 } else {
3457 /* could be improved */
3458 char buf[100];
3459 xmlXPathFormatNumber(val, buf, 100);
3460 ret = xmlStrdup((const xmlChar *) buf);
3461 }
3462 }
3463 return(ret);
3464}
3465
3466/**
3467 * xmlXPathCastNodeToString:
3468 * @node: a node
3469 *
3470 * Converts a node to its string value.
3471 *
3472 * Returns a newly allocated string.
3473 */
3474xmlChar *
3475xmlXPathCastNodeToString (xmlNodePtr node) {
3476 return(xmlNodeGetContent(node));
3477}
3478
3479/**
3480 * xmlXPathCastNodeSetToString:
3481 * @ns: a node-set
3482 *
3483 * Converts a node-set to its string value.
3484 *
3485 * Returns a newly allocated string.
3486 */
3487xmlChar *
3488xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3489 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3490 return(xmlStrdup((const xmlChar *) ""));
3491
3492 xmlXPathNodeSetSort(ns);
3493 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3494}
3495
3496/**
3497 * xmlXPathCastToString:
3498 * @val: an XPath object
3499 *
3500 * Converts an existing object to its string() equivalent
3501 *
3502 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003503 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003504 * string object).
3505 */
3506xmlChar *
3507xmlXPathCastToString(xmlXPathObjectPtr val) {
3508 xmlChar *ret = NULL;
3509
3510 if (val == NULL)
3511 return(xmlStrdup((const xmlChar *) ""));
3512 switch (val->type) {
3513 case XPATH_UNDEFINED:
3514#ifdef DEBUG_EXPR
3515 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3516#endif
3517 ret = xmlStrdup((const xmlChar *) "");
3518 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003519 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003520 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003521 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3522 break;
3523 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003524 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003525 case XPATH_BOOLEAN:
3526 ret = xmlXPathCastBooleanToString(val->boolval);
3527 break;
3528 case XPATH_NUMBER: {
3529 ret = xmlXPathCastNumberToString(val->floatval);
3530 break;
3531 }
3532 case XPATH_USERS:
3533 case XPATH_POINT:
3534 case XPATH_RANGE:
3535 case XPATH_LOCATIONSET:
3536 TODO
3537 ret = xmlStrdup((const xmlChar *) "");
3538 break;
3539 }
3540 return(ret);
3541}
3542
3543/**
3544 * xmlXPathConvertString:
3545 * @val: an XPath object
3546 *
3547 * Converts an existing object to its string() equivalent
3548 *
3549 * Returns the new object, the old one is freed (or the operation
3550 * is done directly on @val)
3551 */
3552xmlXPathObjectPtr
3553xmlXPathConvertString(xmlXPathObjectPtr val) {
3554 xmlChar *res = NULL;
3555
3556 if (val == NULL)
3557 return(xmlXPathNewCString(""));
3558
3559 switch (val->type) {
3560 case XPATH_UNDEFINED:
3561#ifdef DEBUG_EXPR
3562 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3563#endif
3564 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003565 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003566 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003567 res = xmlXPathCastNodeSetToString(val->nodesetval);
3568 break;
3569 case XPATH_STRING:
3570 return(val);
3571 case XPATH_BOOLEAN:
3572 res = xmlXPathCastBooleanToString(val->boolval);
3573 break;
3574 case XPATH_NUMBER:
3575 res = xmlXPathCastNumberToString(val->floatval);
3576 break;
3577 case XPATH_USERS:
3578 case XPATH_POINT:
3579 case XPATH_RANGE:
3580 case XPATH_LOCATIONSET:
3581 TODO;
3582 break;
3583 }
3584 xmlXPathFreeObject(val);
3585 if (res == NULL)
3586 return(xmlXPathNewCString(""));
3587 return(xmlXPathWrapString(res));
3588}
3589
3590/**
3591 * xmlXPathCastBooleanToNumber:
3592 * @val: a boolean
3593 *
3594 * Converts a boolean to its number value
3595 *
3596 * Returns the number value
3597 */
3598double
3599xmlXPathCastBooleanToNumber(int val) {
3600 if (val)
3601 return(1.0);
3602 return(0.0);
3603}
3604
3605/**
3606 * xmlXPathCastStringToNumber:
3607 * @val: a string
3608 *
3609 * Converts a string to its number value
3610 *
3611 * Returns the number value
3612 */
3613double
3614xmlXPathCastStringToNumber(const xmlChar * val) {
3615 return(xmlXPathStringEvalNumber(val));
3616}
3617
3618/**
3619 * xmlXPathCastNodeToNumber:
3620 * @node: a node
3621 *
3622 * Converts a node to its number value
3623 *
3624 * Returns the number value
3625 */
3626double
3627xmlXPathCastNodeToNumber (xmlNodePtr node) {
3628 xmlChar *strval;
3629 double ret;
3630
3631 if (node == NULL)
3632 return(xmlXPathNAN);
3633 strval = xmlXPathCastNodeToString(node);
3634 if (strval == NULL)
3635 return(xmlXPathNAN);
3636 ret = xmlXPathCastStringToNumber(strval);
3637 xmlFree(strval);
3638
3639 return(ret);
3640}
3641
3642/**
3643 * xmlXPathCastNodeSetToNumber:
3644 * @ns: a node-set
3645 *
3646 * Converts a node-set to its number value
3647 *
3648 * Returns the number value
3649 */
3650double
3651xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3652 xmlChar *str;
3653 double ret;
3654
3655 if (ns == NULL)
3656 return(xmlXPathNAN);
3657 str = xmlXPathCastNodeSetToString(ns);
3658 ret = xmlXPathCastStringToNumber(str);
3659 xmlFree(str);
3660 return(ret);
3661}
3662
3663/**
3664 * xmlXPathCastToNumber:
3665 * @val: an XPath object
3666 *
3667 * Converts an XPath object to its number value
3668 *
3669 * Returns the number value
3670 */
3671double
3672xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3673 double ret = 0.0;
3674
3675 if (val == NULL)
3676 return(xmlXPathNAN);
3677 switch (val->type) {
3678 case XPATH_UNDEFINED:
3679#ifdef DEGUB_EXPR
3680 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3681#endif
3682 ret = xmlXPathNAN;
3683 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003684 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003685 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003686 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3687 break;
3688 case XPATH_STRING:
3689 ret = xmlXPathCastStringToNumber(val->stringval);
3690 break;
3691 case XPATH_NUMBER:
3692 ret = val->floatval;
3693 break;
3694 case XPATH_BOOLEAN:
3695 ret = xmlXPathCastBooleanToNumber(val->boolval);
3696 break;
3697 case XPATH_USERS:
3698 case XPATH_POINT:
3699 case XPATH_RANGE:
3700 case XPATH_LOCATIONSET:
3701 TODO;
3702 ret = xmlXPathNAN;
3703 break;
3704 }
3705 return(ret);
3706}
3707
3708/**
3709 * xmlXPathConvertNumber:
3710 * @val: an XPath object
3711 *
3712 * Converts an existing object to its number() equivalent
3713 *
3714 * Returns the new object, the old one is freed (or the operation
3715 * is done directly on @val)
3716 */
3717xmlXPathObjectPtr
3718xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3719 xmlXPathObjectPtr ret;
3720
3721 if (val == NULL)
3722 return(xmlXPathNewFloat(0.0));
3723 if (val->type == XPATH_NUMBER)
3724 return(val);
3725 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3726 xmlXPathFreeObject(val);
3727 return(ret);
3728}
3729
3730/**
3731 * xmlXPathCastNumberToBoolean:
3732 * @val: a number
3733 *
3734 * Converts a number to its boolean value
3735 *
3736 * Returns the boolean value
3737 */
3738int
3739xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003740 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003741 return(0);
3742 return(1);
3743}
3744
3745/**
3746 * xmlXPathCastStringToBoolean:
3747 * @val: a string
3748 *
3749 * Converts a string to its boolean value
3750 *
3751 * Returns the boolean value
3752 */
3753int
3754xmlXPathCastStringToBoolean (const xmlChar *val) {
3755 if ((val == NULL) || (xmlStrlen(val) == 0))
3756 return(0);
3757 return(1);
3758}
3759
3760/**
3761 * xmlXPathCastNodeSetToBoolean:
3762 * @ns: a node-set
3763 *
3764 * Converts a node-set to its boolean value
3765 *
3766 * Returns the boolean value
3767 */
3768int
3769xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3770 if ((ns == NULL) || (ns->nodeNr == 0))
3771 return(0);
3772 return(1);
3773}
3774
3775/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003776 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003777 * @val: an XPath object
3778 *
3779 * Converts an XPath object to its boolean value
3780 *
3781 * Returns the boolean value
3782 */
3783int
3784xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3785 int ret = 0;
3786
3787 if (val == NULL)
3788 return(0);
3789 switch (val->type) {
3790 case XPATH_UNDEFINED:
3791#ifdef DEBUG_EXPR
3792 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3793#endif
3794 ret = 0;
3795 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003796 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003797 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003798 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3799 break;
3800 case XPATH_STRING:
3801 ret = xmlXPathCastStringToBoolean(val->stringval);
3802 break;
3803 case XPATH_NUMBER:
3804 ret = xmlXPathCastNumberToBoolean(val->floatval);
3805 break;
3806 case XPATH_BOOLEAN:
3807 ret = val->boolval;
3808 break;
3809 case XPATH_USERS:
3810 case XPATH_POINT:
3811 case XPATH_RANGE:
3812 case XPATH_LOCATIONSET:
3813 TODO;
3814 ret = 0;
3815 break;
3816 }
3817 return(ret);
3818}
3819
3820
3821/**
3822 * xmlXPathConvertBoolean:
3823 * @val: an XPath object
3824 *
3825 * Converts an existing object to its boolean() equivalent
3826 *
3827 * Returns the new object, the old one is freed (or the operation
3828 * is done directly on @val)
3829 */
3830xmlXPathObjectPtr
3831xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3832 xmlXPathObjectPtr ret;
3833
3834 if (val == NULL)
3835 return(xmlXPathNewBoolean(0));
3836 if (val->type == XPATH_BOOLEAN)
3837 return(val);
3838 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3839 xmlXPathFreeObject(val);
3840 return(ret);
3841}
3842
Owen Taylor3473f882001-02-23 17:55:21 +00003843/************************************************************************
3844 * *
3845 * Routines to handle XPath contexts *
3846 * *
3847 ************************************************************************/
3848
3849/**
3850 * xmlXPathNewContext:
3851 * @doc: the XML document
3852 *
3853 * Create a new xmlXPathContext
3854 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003855 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003856 */
3857xmlXPathContextPtr
3858xmlXPathNewContext(xmlDocPtr doc) {
3859 xmlXPathContextPtr ret;
3860
3861 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3862 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003863 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003864 return(NULL);
3865 }
3866 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3867 ret->doc = doc;
3868 ret->node = NULL;
3869
3870 ret->varHash = NULL;
3871
3872 ret->nb_types = 0;
3873 ret->max_types = 0;
3874 ret->types = NULL;
3875
3876 ret->funcHash = xmlHashCreate(0);
3877
3878 ret->nb_axis = 0;
3879 ret->max_axis = 0;
3880 ret->axis = NULL;
3881
3882 ret->nsHash = NULL;
3883 ret->user = NULL;
3884
3885 ret->contextSize = -1;
3886 ret->proximityPosition = -1;
3887
3888 xmlXPathRegisterAllFunctions(ret);
3889
3890 return(ret);
3891}
3892
3893/**
3894 * xmlXPathFreeContext:
3895 * @ctxt: the context to free
3896 *
3897 * Free up an xmlXPathContext
3898 */
3899void
3900xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3901 xmlXPathRegisteredNsCleanup(ctxt);
3902 xmlXPathRegisteredFuncsCleanup(ctxt);
3903 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003904 xmlFree(ctxt);
3905}
3906
3907/************************************************************************
3908 * *
3909 * Routines to handle XPath parser contexts *
3910 * *
3911 ************************************************************************/
3912
3913#define CHECK_CTXT(ctxt) \
3914 if (ctxt == NULL) { \
3915 xmlGenericError(xmlGenericErrorContext, \
3916 "%s:%d Internal error: ctxt == NULL\n", \
3917 __FILE__, __LINE__); \
3918 } \
3919
3920
3921#define CHECK_CONTEXT(ctxt) \
3922 if (ctxt == NULL) { \
3923 xmlGenericError(xmlGenericErrorContext, \
3924 "%s:%d Internal error: no context\n", \
3925 __FILE__, __LINE__); \
3926 } \
3927 else if (ctxt->doc == NULL) { \
3928 xmlGenericError(xmlGenericErrorContext, \
3929 "%s:%d Internal error: no document\n", \
3930 __FILE__, __LINE__); \
3931 } \
3932 else if (ctxt->doc->children == NULL) { \
3933 xmlGenericError(xmlGenericErrorContext, \
3934 "%s:%d Internal error: document without root\n", \
3935 __FILE__, __LINE__); \
3936 } \
3937
3938
3939/**
3940 * xmlXPathNewParserContext:
3941 * @str: the XPath expression
3942 * @ctxt: the XPath context
3943 *
3944 * Create a new xmlXPathParserContext
3945 *
3946 * Returns the xmlXPathParserContext just allocated.
3947 */
3948xmlXPathParserContextPtr
3949xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3950 xmlXPathParserContextPtr ret;
3951
3952 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3953 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003954 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003955 return(NULL);
3956 }
3957 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3958 ret->cur = ret->base = str;
3959 ret->context = ctxt;
3960
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003961 ret->comp = xmlXPathNewCompExpr();
3962 if (ret->comp == NULL) {
3963 xmlFree(ret->valueTab);
3964 xmlFree(ret);
3965 return(NULL);
3966 }
Daniel Veillard4773df22004-01-23 13:15:13 +00003967 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
3968 ret->comp->dict = ctxt->dict;
3969 xmlDictReference(ret->comp->dict);
3970 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003971
3972 return(ret);
3973}
3974
3975/**
3976 * xmlXPathCompParserContext:
3977 * @comp: the XPath compiled expression
3978 * @ctxt: the XPath context
3979 *
3980 * Create a new xmlXPathParserContext when processing a compiled expression
3981 *
3982 * Returns the xmlXPathParserContext just allocated.
3983 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003984static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003985xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3986 xmlXPathParserContextPtr ret;
3987
3988 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3989 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003990 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003991 return(NULL);
3992 }
3993 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3994
Owen Taylor3473f882001-02-23 17:55:21 +00003995 /* Allocate the value stack */
3996 ret->valueTab = (xmlXPathObjectPtr *)
3997 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003998 if (ret->valueTab == NULL) {
3999 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004000 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004001 return(NULL);
4002 }
Owen Taylor3473f882001-02-23 17:55:21 +00004003 ret->valueNr = 0;
4004 ret->valueMax = 10;
4005 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004006
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004007 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004008 ret->comp = comp;
4009
Owen Taylor3473f882001-02-23 17:55:21 +00004010 return(ret);
4011}
4012
4013/**
4014 * xmlXPathFreeParserContext:
4015 * @ctxt: the context to free
4016 *
4017 * Free up an xmlXPathParserContext
4018 */
4019void
4020xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
4021 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004022 xmlFree(ctxt->valueTab);
4023 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004024 if (ctxt->comp)
4025 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00004026 xmlFree(ctxt);
4027}
4028
4029/************************************************************************
4030 * *
4031 * The implicit core function library *
4032 * *
4033 ************************************************************************/
4034
Owen Taylor3473f882001-02-23 17:55:21 +00004035/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004036 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00004037 * @node: a node pointer
4038 *
4039 * Function computing the beginning of the string value of the node,
4040 * used to speed up comparisons
4041 *
4042 * Returns an int usable as a hash
4043 */
4044static unsigned int
4045xmlXPathNodeValHash(xmlNodePtr node) {
4046 int len = 2;
4047 const xmlChar * string = NULL;
4048 xmlNodePtr tmp = NULL;
4049 unsigned int ret = 0;
4050
4051 if (node == NULL)
4052 return(0);
4053
Daniel Veillard9adc0462003-03-24 18:39:54 +00004054 if (node->type == XML_DOCUMENT_NODE) {
4055 tmp = xmlDocGetRootElement((xmlDocPtr) node);
4056 if (tmp == NULL)
4057 node = node->children;
4058 else
4059 node = tmp;
4060
4061 if (node == NULL)
4062 return(0);
4063 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004064
4065 switch (node->type) {
4066 case XML_COMMENT_NODE:
4067 case XML_PI_NODE:
4068 case XML_CDATA_SECTION_NODE:
4069 case XML_TEXT_NODE:
4070 string = node->content;
4071 if (string == NULL)
4072 return(0);
4073 if (string[0] == 0)
4074 return(0);
4075 return(((unsigned int) string[0]) +
4076 (((unsigned int) string[1]) << 8));
4077 case XML_NAMESPACE_DECL:
4078 string = ((xmlNsPtr)node)->href;
4079 if (string == NULL)
4080 return(0);
4081 if (string[0] == 0)
4082 return(0);
4083 return(((unsigned int) string[0]) +
4084 (((unsigned int) string[1]) << 8));
4085 case XML_ATTRIBUTE_NODE:
4086 tmp = ((xmlAttrPtr) node)->children;
4087 break;
4088 case XML_ELEMENT_NODE:
4089 tmp = node->children;
4090 break;
4091 default:
4092 return(0);
4093 }
4094 while (tmp != NULL) {
4095 switch (tmp->type) {
4096 case XML_COMMENT_NODE:
4097 case XML_PI_NODE:
4098 case XML_CDATA_SECTION_NODE:
4099 case XML_TEXT_NODE:
4100 string = tmp->content;
4101 break;
4102 case XML_NAMESPACE_DECL:
4103 string = ((xmlNsPtr)tmp)->href;
4104 break;
4105 default:
4106 break;
4107 }
4108 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004109 if (len == 1) {
4110 return(ret + (((unsigned int) string[0]) << 8));
4111 }
4112 if (string[1] == 0) {
4113 len = 1;
4114 ret = (unsigned int) string[0];
4115 } else {
4116 return(((unsigned int) string[0]) +
4117 (((unsigned int) string[1]) << 8));
4118 }
4119 }
4120 /*
4121 * Skip to next node
4122 */
4123 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4124 if (tmp->children->type != XML_ENTITY_DECL) {
4125 tmp = tmp->children;
4126 continue;
4127 }
4128 }
4129 if (tmp == node)
4130 break;
4131
4132 if (tmp->next != NULL) {
4133 tmp = tmp->next;
4134 continue;
4135 }
4136
4137 do {
4138 tmp = tmp->parent;
4139 if (tmp == NULL)
4140 break;
4141 if (tmp == node) {
4142 tmp = NULL;
4143 break;
4144 }
4145 if (tmp->next != NULL) {
4146 tmp = tmp->next;
4147 break;
4148 }
4149 } while (tmp != NULL);
4150 }
4151 return(ret);
4152}
4153
4154/**
4155 * xmlXPathStringHash:
4156 * @string: a string
4157 *
4158 * Function computing the beginning of the string value of the node,
4159 * used to speed up comparisons
4160 *
4161 * Returns an int usable as a hash
4162 */
4163static unsigned int
4164xmlXPathStringHash(const xmlChar * string) {
4165 if (string == NULL)
4166 return((unsigned int) 0);
4167 if (string[0] == 0)
4168 return(0);
4169 return(((unsigned int) string[0]) +
4170 (((unsigned int) string[1]) << 8));
4171}
4172
4173/**
Owen Taylor3473f882001-02-23 17:55:21 +00004174 * xmlXPathCompareNodeSetFloat:
4175 * @ctxt: the XPath Parser context
4176 * @inf: less than (1) or greater than (0)
4177 * @strict: is the comparison strict
4178 * @arg: the node set
4179 * @f: the value
4180 *
4181 * Implement the compare operation between a nodeset and a number
4182 * @ns < @val (1, 1, ...
4183 * @ns <= @val (1, 0, ...
4184 * @ns > @val (0, 1, ...
4185 * @ns >= @val (0, 0, ...
4186 *
4187 * If one object to be compared is a node-set and the other is a number,
4188 * then the comparison will be true if and only if there is a node in the
4189 * node-set such that the result of performing the comparison on the number
4190 * to be compared and on the result of converting the string-value of that
4191 * node to a number using the number function is true.
4192 *
4193 * Returns 0 or 1 depending on the results of the test.
4194 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004195static int
Owen Taylor3473f882001-02-23 17:55:21 +00004196xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4197 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4198 int i, ret = 0;
4199 xmlNodeSetPtr ns;
4200 xmlChar *str2;
4201
4202 if ((f == NULL) || (arg == NULL) ||
4203 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4204 xmlXPathFreeObject(arg);
4205 xmlXPathFreeObject(f);
4206 return(0);
4207 }
4208 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004209 if (ns != NULL) {
4210 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004211 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004212 if (str2 != NULL) {
4213 valuePush(ctxt,
4214 xmlXPathNewString(str2));
4215 xmlFree(str2);
4216 xmlXPathNumberFunction(ctxt, 1);
4217 valuePush(ctxt, xmlXPathObjectCopy(f));
4218 ret = xmlXPathCompareValues(ctxt, inf, strict);
4219 if (ret)
4220 break;
4221 }
4222 }
Owen Taylor3473f882001-02-23 17:55:21 +00004223 }
4224 xmlXPathFreeObject(arg);
4225 xmlXPathFreeObject(f);
4226 return(ret);
4227}
4228
4229/**
4230 * xmlXPathCompareNodeSetString:
4231 * @ctxt: the XPath Parser context
4232 * @inf: less than (1) or greater than (0)
4233 * @strict: is the comparison strict
4234 * @arg: the node set
4235 * @s: the value
4236 *
4237 * Implement the compare operation between a nodeset and a string
4238 * @ns < @val (1, 1, ...
4239 * @ns <= @val (1, 0, ...
4240 * @ns > @val (0, 1, ...
4241 * @ns >= @val (0, 0, ...
4242 *
4243 * If one object to be compared is a node-set and the other is a string,
4244 * then the comparison will be true if and only if there is a node in
4245 * the node-set such that the result of performing the comparison on the
4246 * string-value of the node and the other string is true.
4247 *
4248 * Returns 0 or 1 depending on the results of the test.
4249 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004250static int
Owen Taylor3473f882001-02-23 17:55:21 +00004251xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4252 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4253 int i, ret = 0;
4254 xmlNodeSetPtr ns;
4255 xmlChar *str2;
4256
4257 if ((s == NULL) || (arg == NULL) ||
4258 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4259 xmlXPathFreeObject(arg);
4260 xmlXPathFreeObject(s);
4261 return(0);
4262 }
4263 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004264 if (ns != NULL) {
4265 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004266 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004267 if (str2 != NULL) {
4268 valuePush(ctxt,
4269 xmlXPathNewString(str2));
4270 xmlFree(str2);
4271 valuePush(ctxt, xmlXPathObjectCopy(s));
4272 ret = xmlXPathCompareValues(ctxt, inf, strict);
4273 if (ret)
4274 break;
4275 }
4276 }
Owen Taylor3473f882001-02-23 17:55:21 +00004277 }
4278 xmlXPathFreeObject(arg);
4279 xmlXPathFreeObject(s);
4280 return(ret);
4281}
4282
4283/**
4284 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004285 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004286 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004287 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004288 * @arg2: the second node set object
4289 *
4290 * Implement the compare operation on nodesets:
4291 *
4292 * If both objects to be compared are node-sets, then the comparison
4293 * will be true if and only if there is a node in the first node-set
4294 * and a node in the second node-set such that the result of performing
4295 * the comparison on the string-values of the two nodes is true.
4296 * ....
4297 * When neither object to be compared is a node-set and the operator
4298 * is <=, <, >= or >, then the objects are compared by converting both
4299 * objects to numbers and comparing the numbers according to IEEE 754.
4300 * ....
4301 * The number function converts its argument to a number as follows:
4302 * - a string that consists of optional whitespace followed by an
4303 * optional minus sign followed by a Number followed by whitespace
4304 * is converted to the IEEE 754 number that is nearest (according
4305 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4306 * represented by the string; any other string is converted to NaN
4307 *
4308 * Conclusion all nodes need to be converted first to their string value
4309 * and then the comparison must be done when possible
4310 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004311static int
4312xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004313 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4314 int i, j, init = 0;
4315 double val1;
4316 double *values2;
4317 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004318 xmlNodeSetPtr ns1;
4319 xmlNodeSetPtr ns2;
4320
4321 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004322 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4323 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004324 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004325 }
Owen Taylor3473f882001-02-23 17:55:21 +00004326 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004327 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4328 xmlXPathFreeObject(arg1);
4329 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004330 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004331 }
Owen Taylor3473f882001-02-23 17:55:21 +00004332
4333 ns1 = arg1->nodesetval;
4334 ns2 = arg2->nodesetval;
4335
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004336 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004337 xmlXPathFreeObject(arg1);
4338 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004339 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004340 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004341 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004342 xmlXPathFreeObject(arg1);
4343 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004344 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004345 }
Owen Taylor3473f882001-02-23 17:55:21 +00004346
4347 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4348 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004349 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004350 xmlXPathFreeObject(arg1);
4351 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004352 return(0);
4353 }
4354 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004355 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004356 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004357 continue;
4358 for (j = 0;j < ns2->nodeNr;j++) {
4359 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004360 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004361 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004362 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004363 continue;
4364 if (inf && strict)
4365 ret = (val1 < values2[j]);
4366 else 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 if (ret)
4373 break;
4374 }
4375 if (ret)
4376 break;
4377 init = 1;
4378 }
4379 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004380 xmlXPathFreeObject(arg1);
4381 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004382 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004383}
4384
4385/**
4386 * xmlXPathCompareNodeSetValue:
4387 * @ctxt: the XPath Parser context
4388 * @inf: less than (1) or greater than (0)
4389 * @strict: is the comparison strict
4390 * @arg: the node set
4391 * @val: the value
4392 *
4393 * Implement the compare operation between a nodeset and a value
4394 * @ns < @val (1, 1, ...
4395 * @ns <= @val (1, 0, ...
4396 * @ns > @val (0, 1, ...
4397 * @ns >= @val (0, 0, ...
4398 *
4399 * If one object to be compared is a node-set and the other is a boolean,
4400 * then the comparison will be true if and only if the result of performing
4401 * the comparison on the boolean and on the result of converting
4402 * the node-set to a boolean using the boolean function is true.
4403 *
4404 * Returns 0 or 1 depending on the results of the test.
4405 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004406static int
Owen Taylor3473f882001-02-23 17:55:21 +00004407xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4408 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4409 if ((val == NULL) || (arg == NULL) ||
4410 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4411 return(0);
4412
4413 switch(val->type) {
4414 case XPATH_NUMBER:
4415 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4416 case XPATH_NODESET:
4417 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004418 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004419 case XPATH_STRING:
4420 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4421 case XPATH_BOOLEAN:
4422 valuePush(ctxt, arg);
4423 xmlXPathBooleanFunction(ctxt, 1);
4424 valuePush(ctxt, val);
4425 return(xmlXPathCompareValues(ctxt, inf, strict));
4426 default:
4427 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004428 }
4429 return(0);
4430}
4431
4432/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004433 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004434 * @arg: the nodeset object argument
4435 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004436 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004437 *
4438 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4439 * If one object to be compared is a node-set and the other is a string,
4440 * then the comparison will be true if and only if there is a node in
4441 * the node-set such that the result of performing the comparison on the
4442 * string-value of the node and the other string is true.
4443 *
4444 * Returns 0 or 1 depending on the results of the test.
4445 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004446static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004447xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004448{
Owen Taylor3473f882001-02-23 17:55:21 +00004449 int i;
4450 xmlNodeSetPtr ns;
4451 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004452 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004453
4454 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004455 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4456 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004457 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004458 /*
4459 * A NULL nodeset compared with a string is always false
4460 * (since there is no node equal, and no node not equal)
4461 */
4462 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004463 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004464 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004465 for (i = 0; i < ns->nodeNr; i++) {
4466 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4467 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4468 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4469 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004470 if (neq)
4471 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004472 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004473 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4474 if (neq)
4475 continue;
4476 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004477 } else if (neq) {
4478 if (str2 != NULL)
4479 xmlFree(str2);
4480 return (1);
4481 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004482 if (str2 != NULL)
4483 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004484 } else if (neq)
4485 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004486 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004487 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004488}
4489
4490/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004491 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004492 * @arg: the nodeset object argument
4493 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004494 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004495 *
4496 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4497 * If one object to be compared is a node-set and the other is a number,
4498 * then the comparison will be true if and only if there is a node in
4499 * the node-set such that the result of performing the comparison on the
4500 * number to be compared and on the result of converting the string-value
4501 * of that node to a number using the number function is true.
4502 *
4503 * Returns 0 or 1 depending on the results of the test.
4504 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004505static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004506xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4507 xmlXPathObjectPtr arg, double f, int neq) {
4508 int i, ret=0;
4509 xmlNodeSetPtr ns;
4510 xmlChar *str2;
4511 xmlXPathObjectPtr val;
4512 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004513
4514 if ((arg == NULL) ||
4515 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4516 return(0);
4517
William M. Brack0c022ad2002-07-12 00:56:01 +00004518 ns = arg->nodesetval;
4519 if (ns != NULL) {
4520 for (i=0;i<ns->nodeNr;i++) {
4521 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4522 if (str2 != NULL) {
4523 valuePush(ctxt, xmlXPathNewString(str2));
4524 xmlFree(str2);
4525 xmlXPathNumberFunction(ctxt, 1);
4526 val = valuePop(ctxt);
4527 v = val->floatval;
4528 xmlXPathFreeObject(val);
4529 if (!xmlXPathIsNaN(v)) {
4530 if ((!neq) && (v==f)) {
4531 ret = 1;
4532 break;
4533 } else if ((neq) && (v!=f)) {
4534 ret = 1;
4535 break;
4536 }
4537 }
4538 }
4539 }
4540 }
4541
4542 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004543}
4544
4545
4546/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004547 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004548 * @arg1: first nodeset object argument
4549 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004550 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004551 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004552 * Implement the equal / not equal operation on XPath nodesets:
4553 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004554 * If both objects to be compared are node-sets, then the comparison
4555 * will be true if and only if there is a node in the first node-set and
4556 * a node in the second node-set such that the result of performing the
4557 * comparison on the string-values of the two nodes is true.
4558 *
4559 * (needless to say, this is a costly operation)
4560 *
4561 * Returns 0 or 1 depending on the results of the test.
4562 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004563static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004564xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004565 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004566 unsigned int *hashs1;
4567 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004568 xmlChar **values1;
4569 xmlChar **values2;
4570 int ret = 0;
4571 xmlNodeSetPtr ns1;
4572 xmlNodeSetPtr ns2;
4573
4574 if ((arg1 == NULL) ||
4575 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4576 return(0);
4577 if ((arg2 == NULL) ||
4578 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4579 return(0);
4580
4581 ns1 = arg1->nodesetval;
4582 ns2 = arg2->nodesetval;
4583
Daniel Veillard911f49a2001-04-07 15:39:35 +00004584 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004585 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004586 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004587 return(0);
4588
4589 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004590 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004591 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004592 if (neq == 0)
4593 for (i = 0;i < ns1->nodeNr;i++)
4594 for (j = 0;j < ns2->nodeNr;j++)
4595 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4596 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004597
4598 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004599 if (values1 == NULL) {
4600 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004601 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004602 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004603 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4604 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004605 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004606 xmlFree(values1);
4607 return(0);
4608 }
Owen Taylor3473f882001-02-23 17:55:21 +00004609 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4610 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4611 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004612 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004613 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004614 xmlFree(values1);
4615 return(0);
4616 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004617 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4618 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004619 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004620 xmlFree(hashs1);
4621 xmlFree(values1);
4622 xmlFree(values2);
4623 return(0);
4624 }
Owen Taylor3473f882001-02-23 17:55:21 +00004625 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4626 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004627 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004628 for (j = 0;j < ns2->nodeNr;j++) {
4629 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004630 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004631 if (hashs1[i] != hashs2[j]) {
4632 if (neq) {
4633 ret = 1;
4634 break;
4635 }
4636 }
4637 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004638 if (values1[i] == NULL)
4639 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4640 if (values2[j] == NULL)
4641 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004642 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004643 if (ret)
4644 break;
4645 }
Owen Taylor3473f882001-02-23 17:55:21 +00004646 }
4647 if (ret)
4648 break;
4649 }
4650 for (i = 0;i < ns1->nodeNr;i++)
4651 if (values1[i] != NULL)
4652 xmlFree(values1[i]);
4653 for (j = 0;j < ns2->nodeNr;j++)
4654 if (values2[j] != NULL)
4655 xmlFree(values2[j]);
4656 xmlFree(values1);
4657 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004658 xmlFree(hashs1);
4659 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004660 return(ret);
4661}
4662
William M. Brack0c022ad2002-07-12 00:56:01 +00004663static int
4664xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4665 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004666 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004667 /*
4668 *At this point we are assured neither arg1 nor arg2
4669 *is a nodeset, so we can just pick the appropriate routine.
4670 */
Owen Taylor3473f882001-02-23 17:55:21 +00004671 switch (arg1->type) {
4672 case XPATH_UNDEFINED:
4673#ifdef DEBUG_EXPR
4674 xmlGenericError(xmlGenericErrorContext,
4675 "Equal: undefined\n");
4676#endif
4677 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004678 case XPATH_BOOLEAN:
4679 switch (arg2->type) {
4680 case XPATH_UNDEFINED:
4681#ifdef DEBUG_EXPR
4682 xmlGenericError(xmlGenericErrorContext,
4683 "Equal: undefined\n");
4684#endif
4685 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004686 case XPATH_BOOLEAN:
4687#ifdef DEBUG_EXPR
4688 xmlGenericError(xmlGenericErrorContext,
4689 "Equal: %d boolean %d \n",
4690 arg1->boolval, arg2->boolval);
4691#endif
4692 ret = (arg1->boolval == arg2->boolval);
4693 break;
4694 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004695 ret = (arg1->boolval ==
4696 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004697 break;
4698 case XPATH_STRING:
4699 if ((arg2->stringval == NULL) ||
4700 (arg2->stringval[0] == 0)) ret = 0;
4701 else
4702 ret = 1;
4703 ret = (arg1->boolval == ret);
4704 break;
4705 case XPATH_USERS:
4706 case XPATH_POINT:
4707 case XPATH_RANGE:
4708 case XPATH_LOCATIONSET:
4709 TODO
4710 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004711 case XPATH_NODESET:
4712 case XPATH_XSLT_TREE:
4713 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004714 }
4715 break;
4716 case XPATH_NUMBER:
4717 switch (arg2->type) {
4718 case XPATH_UNDEFINED:
4719#ifdef DEBUG_EXPR
4720 xmlGenericError(xmlGenericErrorContext,
4721 "Equal: undefined\n");
4722#endif
4723 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004724 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004725 ret = (arg2->boolval==
4726 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004727 break;
4728 case XPATH_STRING:
4729 valuePush(ctxt, arg2);
4730 xmlXPathNumberFunction(ctxt, 1);
4731 arg2 = valuePop(ctxt);
4732 /* no break on purpose */
4733 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004734 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004735 if (xmlXPathIsNaN(arg1->floatval) ||
4736 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004737 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004738 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4739 if (xmlXPathIsInf(arg2->floatval) == 1)
4740 ret = 1;
4741 else
4742 ret = 0;
4743 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4744 if (xmlXPathIsInf(arg2->floatval) == -1)
4745 ret = 1;
4746 else
4747 ret = 0;
4748 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4749 if (xmlXPathIsInf(arg1->floatval) == 1)
4750 ret = 1;
4751 else
4752 ret = 0;
4753 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4754 if (xmlXPathIsInf(arg1->floatval) == -1)
4755 ret = 1;
4756 else
4757 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004758 } else {
4759 ret = (arg1->floatval == arg2->floatval);
4760 }
Owen Taylor3473f882001-02-23 17:55:21 +00004761 break;
4762 case XPATH_USERS:
4763 case XPATH_POINT:
4764 case XPATH_RANGE:
4765 case XPATH_LOCATIONSET:
4766 TODO
4767 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004768 case XPATH_NODESET:
4769 case XPATH_XSLT_TREE:
4770 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004771 }
4772 break;
4773 case XPATH_STRING:
4774 switch (arg2->type) {
4775 case XPATH_UNDEFINED:
4776#ifdef DEBUG_EXPR
4777 xmlGenericError(xmlGenericErrorContext,
4778 "Equal: undefined\n");
4779#endif
4780 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004781 case XPATH_BOOLEAN:
4782 if ((arg1->stringval == NULL) ||
4783 (arg1->stringval[0] == 0)) ret = 0;
4784 else
4785 ret = 1;
4786 ret = (arg2->boolval == ret);
4787 break;
4788 case XPATH_STRING:
4789 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4790 break;
4791 case XPATH_NUMBER:
4792 valuePush(ctxt, arg1);
4793 xmlXPathNumberFunction(ctxt, 1);
4794 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004795 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004796 if (xmlXPathIsNaN(arg1->floatval) ||
4797 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004798 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004799 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4800 if (xmlXPathIsInf(arg2->floatval) == 1)
4801 ret = 1;
4802 else
4803 ret = 0;
4804 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4805 if (xmlXPathIsInf(arg2->floatval) == -1)
4806 ret = 1;
4807 else
4808 ret = 0;
4809 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4810 if (xmlXPathIsInf(arg1->floatval) == 1)
4811 ret = 1;
4812 else
4813 ret = 0;
4814 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4815 if (xmlXPathIsInf(arg1->floatval) == -1)
4816 ret = 1;
4817 else
4818 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004819 } else {
4820 ret = (arg1->floatval == arg2->floatval);
4821 }
Owen Taylor3473f882001-02-23 17:55:21 +00004822 break;
4823 case XPATH_USERS:
4824 case XPATH_POINT:
4825 case XPATH_RANGE:
4826 case XPATH_LOCATIONSET:
4827 TODO
4828 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004829 case XPATH_NODESET:
4830 case XPATH_XSLT_TREE:
4831 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004832 }
4833 break;
4834 case XPATH_USERS:
4835 case XPATH_POINT:
4836 case XPATH_RANGE:
4837 case XPATH_LOCATIONSET:
4838 TODO
4839 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004840 case XPATH_NODESET:
4841 case XPATH_XSLT_TREE:
4842 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004843 }
4844 xmlXPathFreeObject(arg1);
4845 xmlXPathFreeObject(arg2);
4846 return(ret);
4847}
4848
William M. Brack0c022ad2002-07-12 00:56:01 +00004849/**
4850 * xmlXPathEqualValues:
4851 * @ctxt: the XPath Parser context
4852 *
4853 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4854 *
4855 * Returns 0 or 1 depending on the results of the test.
4856 */
4857int
4858xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4859 xmlXPathObjectPtr arg1, arg2, argtmp;
4860 int ret = 0;
4861
4862 arg2 = valuePop(ctxt);
4863 arg1 = valuePop(ctxt);
4864 if ((arg1 == NULL) || (arg2 == NULL)) {
4865 if (arg1 != NULL)
4866 xmlXPathFreeObject(arg1);
4867 else
4868 xmlXPathFreeObject(arg2);
4869 XP_ERROR0(XPATH_INVALID_OPERAND);
4870 }
4871
4872 if (arg1 == arg2) {
4873#ifdef DEBUG_EXPR
4874 xmlGenericError(xmlGenericErrorContext,
4875 "Equal: by pointer\n");
4876#endif
4877 return(1);
4878 }
4879
4880 /*
4881 *If either argument is a nodeset, it's a 'special case'
4882 */
4883 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4884 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4885 /*
4886 *Hack it to assure arg1 is the nodeset
4887 */
4888 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4889 argtmp = arg2;
4890 arg2 = arg1;
4891 arg1 = argtmp;
4892 }
4893 switch (arg2->type) {
4894 case XPATH_UNDEFINED:
4895#ifdef DEBUG_EXPR
4896 xmlGenericError(xmlGenericErrorContext,
4897 "Equal: undefined\n");
4898#endif
4899 break;
4900 case XPATH_NODESET:
4901 case XPATH_XSLT_TREE:
4902 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4903 break;
4904 case XPATH_BOOLEAN:
4905 if ((arg1->nodesetval == NULL) ||
4906 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4907 else
4908 ret = 1;
4909 ret = (ret == arg2->boolval);
4910 break;
4911 case XPATH_NUMBER:
4912 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4913 break;
4914 case XPATH_STRING:
4915 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4916 break;
4917 case XPATH_USERS:
4918 case XPATH_POINT:
4919 case XPATH_RANGE:
4920 case XPATH_LOCATIONSET:
4921 TODO
4922 break;
4923 }
4924 xmlXPathFreeObject(arg1);
4925 xmlXPathFreeObject(arg2);
4926 return(ret);
4927 }
4928
4929 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4930}
4931
4932/**
4933 * xmlXPathNotEqualValues:
4934 * @ctxt: the XPath Parser context
4935 *
4936 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4937 *
4938 * Returns 0 or 1 depending on the results of the test.
4939 */
4940int
4941xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4942 xmlXPathObjectPtr arg1, arg2, argtmp;
4943 int ret = 0;
4944
4945 arg2 = valuePop(ctxt);
4946 arg1 = valuePop(ctxt);
4947 if ((arg1 == NULL) || (arg2 == NULL)) {
4948 if (arg1 != NULL)
4949 xmlXPathFreeObject(arg1);
4950 else
4951 xmlXPathFreeObject(arg2);
4952 XP_ERROR0(XPATH_INVALID_OPERAND);
4953 }
4954
4955 if (arg1 == arg2) {
4956#ifdef DEBUG_EXPR
4957 xmlGenericError(xmlGenericErrorContext,
4958 "NotEqual: by pointer\n");
4959#endif
4960 return(0);
4961 }
4962
4963 /*
4964 *If either argument is a nodeset, it's a 'special case'
4965 */
4966 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4967 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4968 /*
4969 *Hack it to assure arg1 is the nodeset
4970 */
4971 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4972 argtmp = arg2;
4973 arg2 = arg1;
4974 arg1 = argtmp;
4975 }
4976 switch (arg2->type) {
4977 case XPATH_UNDEFINED:
4978#ifdef DEBUG_EXPR
4979 xmlGenericError(xmlGenericErrorContext,
4980 "NotEqual: undefined\n");
4981#endif
4982 break;
4983 case XPATH_NODESET:
4984 case XPATH_XSLT_TREE:
4985 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4986 break;
4987 case XPATH_BOOLEAN:
4988 if ((arg1->nodesetval == NULL) ||
4989 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4990 else
4991 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004992 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004993 break;
4994 case XPATH_NUMBER:
4995 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4996 break;
4997 case XPATH_STRING:
4998 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4999 break;
5000 case XPATH_USERS:
5001 case XPATH_POINT:
5002 case XPATH_RANGE:
5003 case XPATH_LOCATIONSET:
5004 TODO
5005 break;
5006 }
5007 xmlXPathFreeObject(arg1);
5008 xmlXPathFreeObject(arg2);
5009 return(ret);
5010 }
5011
5012 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5013}
Owen Taylor3473f882001-02-23 17:55:21 +00005014
5015/**
5016 * xmlXPathCompareValues:
5017 * @ctxt: the XPath Parser context
5018 * @inf: less than (1) or greater than (0)
5019 * @strict: is the comparison strict
5020 *
5021 * Implement the compare operation on XPath objects:
5022 * @arg1 < @arg2 (1, 1, ...
5023 * @arg1 <= @arg2 (1, 0, ...
5024 * @arg1 > @arg2 (0, 1, ...
5025 * @arg1 >= @arg2 (0, 0, ...
5026 *
5027 * When neither object to be compared is a node-set and the operator is
5028 * <=, <, >=, >, then the objects are compared by converted both objects
5029 * to numbers and comparing the numbers according to IEEE 754. The <
5030 * comparison will be true if and only if the first number is less than the
5031 * second number. The <= comparison will be true if and only if the first
5032 * number is less than or equal to the second number. The > comparison
5033 * will be true if and only if the first number is greater than the second
5034 * number. The >= comparison will be true if and only if the first number
5035 * is greater than or equal to the second number.
5036 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005037 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005038 */
5039int
5040xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005041 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005042 xmlXPathObjectPtr arg1, arg2;
5043
William M. Brack0c022ad2002-07-12 00:56:01 +00005044 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005045 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005046 if ((arg1 == NULL) || (arg2 == NULL)) {
5047 if (arg1 != NULL)
5048 xmlXPathFreeObject(arg1);
5049 else
5050 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005051 XP_ERROR0(XPATH_INVALID_OPERAND);
5052 }
5053
William M. Brack0c022ad2002-07-12 00:56:01 +00005054 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5055 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5056 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5057 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005058 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005059 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005060 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005061 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5062 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005063 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005064 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5065 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005066 }
5067 }
5068 return(ret);
5069 }
5070
5071 if (arg1->type != XPATH_NUMBER) {
5072 valuePush(ctxt, arg1);
5073 xmlXPathNumberFunction(ctxt, 1);
5074 arg1 = valuePop(ctxt);
5075 }
5076 if (arg1->type != XPATH_NUMBER) {
5077 xmlXPathFreeObject(arg1);
5078 xmlXPathFreeObject(arg2);
5079 XP_ERROR0(XPATH_INVALID_OPERAND);
5080 }
5081 if (arg2->type != XPATH_NUMBER) {
5082 valuePush(ctxt, arg2);
5083 xmlXPathNumberFunction(ctxt, 1);
5084 arg2 = valuePop(ctxt);
5085 }
5086 if (arg2->type != XPATH_NUMBER) {
5087 xmlXPathFreeObject(arg1);
5088 xmlXPathFreeObject(arg2);
5089 XP_ERROR0(XPATH_INVALID_OPERAND);
5090 }
5091 /*
5092 * Add tests for infinity and nan
5093 * => feedback on 3.4 for Inf and NaN
5094 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005095 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005096 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005097 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005098 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005099 arg1i=xmlXPathIsInf(arg1->floatval);
5100 arg2i=xmlXPathIsInf(arg2->floatval);
5101 if (inf && strict) {
5102 if ((arg1i == -1 && arg2i != -1) ||
5103 (arg2i == 1 && arg1i != 1)) {
5104 ret = 1;
5105 } else if (arg1i == 0 && arg2i == 0) {
5106 ret = (arg1->floatval < arg2->floatval);
5107 } else {
5108 ret = 0;
5109 }
5110 }
5111 else if (inf && !strict) {
5112 if (arg1i == -1 || arg2i == 1) {
5113 ret = 1;
5114 } else if (arg1i == 0 && arg2i == 0) {
5115 ret = (arg1->floatval <= arg2->floatval);
5116 } else {
5117 ret = 0;
5118 }
5119 }
5120 else if (!inf && strict) {
5121 if ((arg1i == 1 && arg2i != 1) ||
5122 (arg2i == -1 && arg1i != -1)) {
5123 ret = 1;
5124 } else if (arg1i == 0 && arg2i == 0) {
5125 ret = (arg1->floatval > arg2->floatval);
5126 } else {
5127 ret = 0;
5128 }
5129 }
5130 else if (!inf && !strict) {
5131 if (arg1i == 1 || arg2i == -1) {
5132 ret = 1;
5133 } else if (arg1i == 0 && arg2i == 0) {
5134 ret = (arg1->floatval >= arg2->floatval);
5135 } else {
5136 ret = 0;
5137 }
5138 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005139 }
Owen Taylor3473f882001-02-23 17:55:21 +00005140 xmlXPathFreeObject(arg1);
5141 xmlXPathFreeObject(arg2);
5142 return(ret);
5143}
5144
5145/**
5146 * xmlXPathValueFlipSign:
5147 * @ctxt: the XPath Parser context
5148 *
5149 * Implement the unary - operation on an XPath object
5150 * The numeric operators convert their operands to numbers as if
5151 * by calling the number function.
5152 */
5153void
5154xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005155 CAST_TO_NUMBER;
5156 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005157 if (xmlXPathIsNaN(ctxt->value->floatval))
5158 ctxt->value->floatval=xmlXPathNAN;
5159 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5160 ctxt->value->floatval=xmlXPathNINF;
5161 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5162 ctxt->value->floatval=xmlXPathPINF;
5163 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005164 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5165 ctxt->value->floatval = xmlXPathNZERO;
5166 else
5167 ctxt->value->floatval = 0;
5168 }
5169 else
5170 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005171}
5172
5173/**
5174 * xmlXPathAddValues:
5175 * @ctxt: the XPath Parser context
5176 *
5177 * Implement the add operation on XPath objects:
5178 * The numeric operators convert their operands to numbers as if
5179 * by calling the number function.
5180 */
5181void
5182xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5183 xmlXPathObjectPtr arg;
5184 double val;
5185
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005186 arg = valuePop(ctxt);
5187 if (arg == NULL)
5188 XP_ERROR(XPATH_INVALID_OPERAND);
5189 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005190 xmlXPathFreeObject(arg);
5191
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005192 CAST_TO_NUMBER;
5193 CHECK_TYPE(XPATH_NUMBER);
5194 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005195}
5196
5197/**
5198 * xmlXPathSubValues:
5199 * @ctxt: the XPath Parser context
5200 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005201 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005202 * The numeric operators convert their operands to numbers as if
5203 * by calling the number function.
5204 */
5205void
5206xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5207 xmlXPathObjectPtr arg;
5208 double val;
5209
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005210 arg = valuePop(ctxt);
5211 if (arg == NULL)
5212 XP_ERROR(XPATH_INVALID_OPERAND);
5213 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005214 xmlXPathFreeObject(arg);
5215
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005216 CAST_TO_NUMBER;
5217 CHECK_TYPE(XPATH_NUMBER);
5218 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005219}
5220
5221/**
5222 * xmlXPathMultValues:
5223 * @ctxt: the XPath Parser context
5224 *
5225 * Implement the multiply operation on XPath objects:
5226 * The numeric operators convert their operands to numbers as if
5227 * by calling the number function.
5228 */
5229void
5230xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5231 xmlXPathObjectPtr arg;
5232 double val;
5233
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005234 arg = valuePop(ctxt);
5235 if (arg == NULL)
5236 XP_ERROR(XPATH_INVALID_OPERAND);
5237 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005238 xmlXPathFreeObject(arg);
5239
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005240 CAST_TO_NUMBER;
5241 CHECK_TYPE(XPATH_NUMBER);
5242 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005243}
5244
5245/**
5246 * xmlXPathDivValues:
5247 * @ctxt: the XPath Parser context
5248 *
5249 * Implement the div operation on XPath objects @arg1 / @arg2:
5250 * The numeric operators convert their operands to numbers as if
5251 * by calling the number function.
5252 */
5253void
5254xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5255 xmlXPathObjectPtr arg;
5256 double val;
5257
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005258 arg = valuePop(ctxt);
5259 if (arg == NULL)
5260 XP_ERROR(XPATH_INVALID_OPERAND);
5261 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005262 xmlXPathFreeObject(arg);
5263
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005264 CAST_TO_NUMBER;
5265 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005266 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5267 ctxt->value->floatval = xmlXPathNAN;
5268 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005269 if (ctxt->value->floatval == 0)
5270 ctxt->value->floatval = xmlXPathNAN;
5271 else if (ctxt->value->floatval > 0)
5272 ctxt->value->floatval = xmlXPathNINF;
5273 else if (ctxt->value->floatval < 0)
5274 ctxt->value->floatval = xmlXPathPINF;
5275 }
5276 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005277 if (ctxt->value->floatval == 0)
5278 ctxt->value->floatval = xmlXPathNAN;
5279 else if (ctxt->value->floatval > 0)
5280 ctxt->value->floatval = xmlXPathPINF;
5281 else if (ctxt->value->floatval < 0)
5282 ctxt->value->floatval = xmlXPathNINF;
5283 } else
5284 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005285}
5286
5287/**
5288 * xmlXPathModValues:
5289 * @ctxt: the XPath Parser context
5290 *
5291 * Implement the mod operation on XPath objects: @arg1 / @arg2
5292 * The numeric operators convert their operands to numbers as if
5293 * by calling the number function.
5294 */
5295void
5296xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5297 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005298 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005299
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005300 arg = valuePop(ctxt);
5301 if (arg == NULL)
5302 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005303 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005304 xmlXPathFreeObject(arg);
5305
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005306 CAST_TO_NUMBER;
5307 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005308 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005309 if (arg2 == 0)
5310 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005311 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005312 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005313 }
Owen Taylor3473f882001-02-23 17:55:21 +00005314}
5315
5316/************************************************************************
5317 * *
5318 * The traversal functions *
5319 * *
5320 ************************************************************************/
5321
Owen Taylor3473f882001-02-23 17:55:21 +00005322/*
5323 * A traversal function enumerates nodes along an axis.
5324 * Initially it must be called with NULL, and it indicates
5325 * termination on the axis by returning NULL.
5326 */
5327typedef xmlNodePtr (*xmlXPathTraversalFunction)
5328 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5329
5330/**
5331 * xmlXPathNextSelf:
5332 * @ctxt: the XPath Parser context
5333 * @cur: the current node in the traversal
5334 *
5335 * Traversal function for the "self" direction
5336 * The self axis contains just the context node itself
5337 *
5338 * Returns the next element following that axis
5339 */
5340xmlNodePtr
5341xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5342 if (cur == NULL)
5343 return(ctxt->context->node);
5344 return(NULL);
5345}
5346
5347/**
5348 * xmlXPathNextChild:
5349 * @ctxt: the XPath Parser context
5350 * @cur: the current node in the traversal
5351 *
5352 * Traversal function for the "child" direction
5353 * The child axis contains the children of the context node in document order.
5354 *
5355 * Returns the next element following that axis
5356 */
5357xmlNodePtr
5358xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5359 if (cur == NULL) {
5360 if (ctxt->context->node == NULL) return(NULL);
5361 switch (ctxt->context->node->type) {
5362 case XML_ELEMENT_NODE:
5363 case XML_TEXT_NODE:
5364 case XML_CDATA_SECTION_NODE:
5365 case XML_ENTITY_REF_NODE:
5366 case XML_ENTITY_NODE:
5367 case XML_PI_NODE:
5368 case XML_COMMENT_NODE:
5369 case XML_NOTATION_NODE:
5370 case XML_DTD_NODE:
5371 return(ctxt->context->node->children);
5372 case XML_DOCUMENT_NODE:
5373 case XML_DOCUMENT_TYPE_NODE:
5374 case XML_DOCUMENT_FRAG_NODE:
5375 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005376#ifdef LIBXML_DOCB_ENABLED
5377 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005378#endif
5379 return(((xmlDocPtr) ctxt->context->node)->children);
5380 case XML_ELEMENT_DECL:
5381 case XML_ATTRIBUTE_DECL:
5382 case XML_ENTITY_DECL:
5383 case XML_ATTRIBUTE_NODE:
5384 case XML_NAMESPACE_DECL:
5385 case XML_XINCLUDE_START:
5386 case XML_XINCLUDE_END:
5387 return(NULL);
5388 }
5389 return(NULL);
5390 }
5391 if ((cur->type == XML_DOCUMENT_NODE) ||
5392 (cur->type == XML_HTML_DOCUMENT_NODE))
5393 return(NULL);
5394 return(cur->next);
5395}
5396
5397/**
5398 * xmlXPathNextDescendant:
5399 * @ctxt: the XPath Parser context
5400 * @cur: the current node in the traversal
5401 *
5402 * Traversal function for the "descendant" direction
5403 * the descendant axis contains the descendants of the context node in document
5404 * order; a descendant is a child or a child of a child and so on.
5405 *
5406 * Returns the next element following that axis
5407 */
5408xmlNodePtr
5409xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5410 if (cur == NULL) {
5411 if (ctxt->context->node == NULL)
5412 return(NULL);
5413 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5414 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5415 return(NULL);
5416
5417 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5418 return(ctxt->context->doc->children);
5419 return(ctxt->context->node->children);
5420 }
5421
Daniel Veillard567e1b42001-08-01 15:53:47 +00005422 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005423 /*
5424 * Do not descend on entities declarations
5425 */
5426 if (cur->children->type != XML_ENTITY_DECL) {
5427 cur = cur->children;
5428 /*
5429 * Skip DTDs
5430 */
5431 if (cur->type != XML_DTD_NODE)
5432 return(cur);
5433 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005434 }
5435
5436 if (cur == ctxt->context->node) return(NULL);
5437
Daniel Veillard68e9e742002-11-16 15:35:11 +00005438 while (cur->next != NULL) {
5439 cur = cur->next;
5440 if ((cur->type != XML_ENTITY_DECL) &&
5441 (cur->type != XML_DTD_NODE))
5442 return(cur);
5443 }
Owen Taylor3473f882001-02-23 17:55:21 +00005444
5445 do {
5446 cur = cur->parent;
5447 if (cur == NULL) return(NULL);
5448 if (cur == ctxt->context->node) return(NULL);
5449 if (cur->next != NULL) {
5450 cur = cur->next;
5451 return(cur);
5452 }
5453 } while (cur != NULL);
5454 return(cur);
5455}
5456
5457/**
5458 * xmlXPathNextDescendantOrSelf:
5459 * @ctxt: the XPath Parser context
5460 * @cur: the current node in the traversal
5461 *
5462 * Traversal function for the "descendant-or-self" direction
5463 * the descendant-or-self axis contains the context node and the descendants
5464 * of the context node in document order; thus the context node is the first
5465 * node on the axis, and the first child of the context node is the second node
5466 * on the axis
5467 *
5468 * Returns the next element following that axis
5469 */
5470xmlNodePtr
5471xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5472 if (cur == NULL) {
5473 if (ctxt->context->node == NULL)
5474 return(NULL);
5475 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5476 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5477 return(NULL);
5478 return(ctxt->context->node);
5479 }
5480
5481 return(xmlXPathNextDescendant(ctxt, cur));
5482}
5483
5484/**
5485 * xmlXPathNextParent:
5486 * @ctxt: the XPath Parser context
5487 * @cur: the current node in the traversal
5488 *
5489 * Traversal function for the "parent" direction
5490 * The parent axis contains the parent of the context node, if there is one.
5491 *
5492 * Returns the next element following that axis
5493 */
5494xmlNodePtr
5495xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5496 /*
5497 * the parent of an attribute or namespace node is the element
5498 * to which the attribute or namespace node is attached
5499 * Namespace handling !!!
5500 */
5501 if (cur == NULL) {
5502 if (ctxt->context->node == NULL) return(NULL);
5503 switch (ctxt->context->node->type) {
5504 case XML_ELEMENT_NODE:
5505 case XML_TEXT_NODE:
5506 case XML_CDATA_SECTION_NODE:
5507 case XML_ENTITY_REF_NODE:
5508 case XML_ENTITY_NODE:
5509 case XML_PI_NODE:
5510 case XML_COMMENT_NODE:
5511 case XML_NOTATION_NODE:
5512 case XML_DTD_NODE:
5513 case XML_ELEMENT_DECL:
5514 case XML_ATTRIBUTE_DECL:
5515 case XML_XINCLUDE_START:
5516 case XML_XINCLUDE_END:
5517 case XML_ENTITY_DECL:
5518 if (ctxt->context->node->parent == NULL)
5519 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005520 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005521 ((ctxt->context->node->parent->name[0] == ' ') ||
5522 (xmlStrEqual(ctxt->context->node->parent->name,
5523 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005524 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005525 return(ctxt->context->node->parent);
5526 case XML_ATTRIBUTE_NODE: {
5527 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5528
5529 return(att->parent);
5530 }
5531 case XML_DOCUMENT_NODE:
5532 case XML_DOCUMENT_TYPE_NODE:
5533 case XML_DOCUMENT_FRAG_NODE:
5534 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005535#ifdef LIBXML_DOCB_ENABLED
5536 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005537#endif
5538 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005539 case XML_NAMESPACE_DECL: {
5540 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5541
5542 if ((ns->next != NULL) &&
5543 (ns->next->type != XML_NAMESPACE_DECL))
5544 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005545 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005546 }
Owen Taylor3473f882001-02-23 17:55:21 +00005547 }
5548 }
5549 return(NULL);
5550}
5551
5552/**
5553 * xmlXPathNextAncestor:
5554 * @ctxt: the XPath Parser context
5555 * @cur: the current node in the traversal
5556 *
5557 * Traversal function for the "ancestor" direction
5558 * the ancestor axis contains the ancestors of the context node; the ancestors
5559 * of the context node consist of the parent of context node and the parent's
5560 * parent and so on; the nodes are ordered in reverse document order; thus the
5561 * parent is the first node on the axis, and the parent's parent is the second
5562 * node on the axis
5563 *
5564 * Returns the next element following that axis
5565 */
5566xmlNodePtr
5567xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5568 /*
5569 * the parent of an attribute or namespace node is the element
5570 * to which the attribute or namespace node is attached
5571 * !!!!!!!!!!!!!
5572 */
5573 if (cur == NULL) {
5574 if (ctxt->context->node == NULL) return(NULL);
5575 switch (ctxt->context->node->type) {
5576 case XML_ELEMENT_NODE:
5577 case XML_TEXT_NODE:
5578 case XML_CDATA_SECTION_NODE:
5579 case XML_ENTITY_REF_NODE:
5580 case XML_ENTITY_NODE:
5581 case XML_PI_NODE:
5582 case XML_COMMENT_NODE:
5583 case XML_DTD_NODE:
5584 case XML_ELEMENT_DECL:
5585 case XML_ATTRIBUTE_DECL:
5586 case XML_ENTITY_DECL:
5587 case XML_NOTATION_NODE:
5588 case XML_XINCLUDE_START:
5589 case XML_XINCLUDE_END:
5590 if (ctxt->context->node->parent == NULL)
5591 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005592 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005593 ((ctxt->context->node->parent->name[0] == ' ') ||
5594 (xmlStrEqual(ctxt->context->node->parent->name,
5595 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005596 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005597 return(ctxt->context->node->parent);
5598 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005599 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005600
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005601 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005602 }
5603 case XML_DOCUMENT_NODE:
5604 case XML_DOCUMENT_TYPE_NODE:
5605 case XML_DOCUMENT_FRAG_NODE:
5606 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005607#ifdef LIBXML_DOCB_ENABLED
5608 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005609#endif
5610 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005611 case XML_NAMESPACE_DECL: {
5612 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5613
5614 if ((ns->next != NULL) &&
5615 (ns->next->type != XML_NAMESPACE_DECL))
5616 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005617 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005618 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005619 }
Owen Taylor3473f882001-02-23 17:55:21 +00005620 }
5621 return(NULL);
5622 }
5623 if (cur == ctxt->context->doc->children)
5624 return((xmlNodePtr) ctxt->context->doc);
5625 if (cur == (xmlNodePtr) ctxt->context->doc)
5626 return(NULL);
5627 switch (cur->type) {
5628 case XML_ELEMENT_NODE:
5629 case XML_TEXT_NODE:
5630 case XML_CDATA_SECTION_NODE:
5631 case XML_ENTITY_REF_NODE:
5632 case XML_ENTITY_NODE:
5633 case XML_PI_NODE:
5634 case XML_COMMENT_NODE:
5635 case XML_NOTATION_NODE:
5636 case XML_DTD_NODE:
5637 case XML_ELEMENT_DECL:
5638 case XML_ATTRIBUTE_DECL:
5639 case XML_ENTITY_DECL:
5640 case XML_XINCLUDE_START:
5641 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005642 if (cur->parent == NULL)
5643 return(NULL);
5644 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005645 ((cur->parent->name[0] == ' ') ||
5646 (xmlStrEqual(cur->parent->name,
5647 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005648 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005649 return(cur->parent);
5650 case XML_ATTRIBUTE_NODE: {
5651 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5652
5653 return(att->parent);
5654 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005655 case XML_NAMESPACE_DECL: {
5656 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5657
5658 if ((ns->next != NULL) &&
5659 (ns->next->type != XML_NAMESPACE_DECL))
5660 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005661 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005662 return(NULL);
5663 }
Owen Taylor3473f882001-02-23 17:55:21 +00005664 case XML_DOCUMENT_NODE:
5665 case XML_DOCUMENT_TYPE_NODE:
5666 case XML_DOCUMENT_FRAG_NODE:
5667 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005668#ifdef LIBXML_DOCB_ENABLED
5669 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005670#endif
5671 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005672 }
5673 return(NULL);
5674}
5675
5676/**
5677 * xmlXPathNextAncestorOrSelf:
5678 * @ctxt: the XPath Parser context
5679 * @cur: the current node in the traversal
5680 *
5681 * Traversal function for the "ancestor-or-self" direction
5682 * he ancestor-or-self axis contains the context node and ancestors of
5683 * the context node in reverse document order; thus the context node is
5684 * the first node on the axis, and the context node's parent the second;
5685 * parent here is defined the same as with the parent axis.
5686 *
5687 * Returns the next element following that axis
5688 */
5689xmlNodePtr
5690xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5691 if (cur == NULL)
5692 return(ctxt->context->node);
5693 return(xmlXPathNextAncestor(ctxt, cur));
5694}
5695
5696/**
5697 * xmlXPathNextFollowingSibling:
5698 * @ctxt: the XPath Parser context
5699 * @cur: the current node in the traversal
5700 *
5701 * Traversal function for the "following-sibling" direction
5702 * The following-sibling axis contains the following siblings of the context
5703 * node in document order.
5704 *
5705 * Returns the next element following that axis
5706 */
5707xmlNodePtr
5708xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5709 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5710 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5711 return(NULL);
5712 if (cur == (xmlNodePtr) ctxt->context->doc)
5713 return(NULL);
5714 if (cur == NULL)
5715 return(ctxt->context->node->next);
5716 return(cur->next);
5717}
5718
5719/**
5720 * xmlXPathNextPrecedingSibling:
5721 * @ctxt: the XPath Parser context
5722 * @cur: the current node in the traversal
5723 *
5724 * Traversal function for the "preceding-sibling" direction
5725 * The preceding-sibling axis contains the preceding siblings of the context
5726 * node in reverse document order; the first preceding sibling is first on the
5727 * axis; the sibling preceding that node is the second on the axis and so on.
5728 *
5729 * Returns the next element following that axis
5730 */
5731xmlNodePtr
5732xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5733 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5734 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5735 return(NULL);
5736 if (cur == (xmlNodePtr) ctxt->context->doc)
5737 return(NULL);
5738 if (cur == NULL)
5739 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005740 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5741 cur = cur->prev;
5742 if (cur == NULL)
5743 return(ctxt->context->node->prev);
5744 }
Owen Taylor3473f882001-02-23 17:55:21 +00005745 return(cur->prev);
5746}
5747
5748/**
5749 * xmlXPathNextFollowing:
5750 * @ctxt: the XPath Parser context
5751 * @cur: the current node in the traversal
5752 *
5753 * Traversal function for the "following" direction
5754 * The following axis contains all nodes in the same document as the context
5755 * node that are after the context node in document order, excluding any
5756 * descendants and excluding attribute nodes and namespace nodes; the nodes
5757 * are ordered in document order
5758 *
5759 * Returns the next element following that axis
5760 */
5761xmlNodePtr
5762xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5763 if (cur != NULL && cur->children != NULL)
5764 return cur->children ;
5765 if (cur == NULL) cur = ctxt->context->node;
5766 if (cur == NULL) return(NULL) ; /* ERROR */
5767 if (cur->next != NULL) return(cur->next) ;
5768 do {
5769 cur = cur->parent;
5770 if (cur == NULL) return(NULL);
5771 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5772 if (cur->next != NULL) return(cur->next);
5773 } while (cur != NULL);
5774 return(cur);
5775}
5776
5777/*
5778 * xmlXPathIsAncestor:
5779 * @ancestor: the ancestor node
5780 * @node: the current node
5781 *
5782 * Check that @ancestor is a @node's ancestor
5783 *
5784 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5785 */
5786static int
5787xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5788 if ((ancestor == NULL) || (node == NULL)) return(0);
5789 /* nodes need to be in the same document */
5790 if (ancestor->doc != node->doc) return(0);
5791 /* avoid searching if ancestor or node is the root node */
5792 if (ancestor == (xmlNodePtr) node->doc) return(1);
5793 if (node == (xmlNodePtr) ancestor->doc) return(0);
5794 while (node->parent != NULL) {
5795 if (node->parent == ancestor)
5796 return(1);
5797 node = node->parent;
5798 }
5799 return(0);
5800}
5801
5802/**
5803 * xmlXPathNextPreceding:
5804 * @ctxt: the XPath Parser context
5805 * @cur: the current node in the traversal
5806 *
5807 * Traversal function for the "preceding" direction
5808 * the preceding axis contains all nodes in the same document as the context
5809 * node that are before the context node in document order, excluding any
5810 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5811 * ordered in reverse document order
5812 *
5813 * Returns the next element following that axis
5814 */
5815xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005816xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5817{
Owen Taylor3473f882001-02-23 17:55:21 +00005818 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005819 cur = ctxt->context->node;
5820 if (cur == NULL)
5821 return (NULL);
5822 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5823 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005824 do {
5825 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005826 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5827 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005828 }
5829
5830 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005831 if (cur == NULL)
5832 return (NULL);
5833 if (cur == ctxt->context->doc->children)
5834 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005835 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005836 return (cur);
5837}
5838
5839/**
5840 * xmlXPathNextPrecedingInternal:
5841 * @ctxt: the XPath Parser context
5842 * @cur: the current node in the traversal
5843 *
5844 * Traversal function for the "preceding" direction
5845 * the preceding axis contains all nodes in the same document as the context
5846 * node that are before the context node in document order, excluding any
5847 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5848 * ordered in reverse document order
5849 * This is a faster implementation but internal only since it requires a
5850 * state kept in the parser context: ctxt->ancestor.
5851 *
5852 * Returns the next element following that axis
5853 */
5854static xmlNodePtr
5855xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5856 xmlNodePtr cur)
5857{
5858 if (cur == NULL) {
5859 cur = ctxt->context->node;
5860 if (cur == NULL)
5861 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005862 if (cur->type == XML_NAMESPACE_DECL)
5863 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005864 ctxt->ancestor = cur->parent;
5865 }
5866 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5867 cur = cur->prev;
5868 while (cur->prev == NULL) {
5869 cur = cur->parent;
5870 if (cur == NULL)
5871 return (NULL);
5872 if (cur == ctxt->context->doc->children)
5873 return (NULL);
5874 if (cur != ctxt->ancestor)
5875 return (cur);
5876 ctxt->ancestor = cur->parent;
5877 }
5878 cur = cur->prev;
5879 while (cur->last != NULL)
5880 cur = cur->last;
5881 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005882}
5883
5884/**
5885 * xmlXPathNextNamespace:
5886 * @ctxt: the XPath Parser context
5887 * @cur: the current attribute in the traversal
5888 *
5889 * Traversal function for the "namespace" direction
5890 * the namespace axis contains the namespace nodes of the context node;
5891 * the order of nodes on this axis is implementation-defined; the axis will
5892 * be empty unless the context node is an element
5893 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005894 * We keep the XML namespace node at the end of the list.
5895 *
Owen Taylor3473f882001-02-23 17:55:21 +00005896 * Returns the next element following that axis
5897 */
5898xmlNodePtr
5899xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5900 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005901 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005902 if (ctxt->context->tmpNsList != NULL)
5903 xmlFree(ctxt->context->tmpNsList);
5904 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005905 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005906 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005907 if (ctxt->context->tmpNsList != NULL) {
5908 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5909 ctxt->context->tmpNsNr++;
5910 }
5911 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005912 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005913 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005914 if (ctxt->context->tmpNsNr > 0) {
5915 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5916 } else {
5917 if (ctxt->context->tmpNsList != NULL)
5918 xmlFree(ctxt->context->tmpNsList);
5919 ctxt->context->tmpNsList = NULL;
5920 return(NULL);
5921 }
Owen Taylor3473f882001-02-23 17:55:21 +00005922}
5923
5924/**
5925 * xmlXPathNextAttribute:
5926 * @ctxt: the XPath Parser context
5927 * @cur: the current attribute in the traversal
5928 *
5929 * Traversal function for the "attribute" direction
5930 * TODO: support DTD inherited default attributes
5931 *
5932 * Returns the next element following that axis
5933 */
5934xmlNodePtr
5935xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005936 if (ctxt->context->node == NULL)
5937 return(NULL);
5938 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5939 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005940 if (cur == NULL) {
5941 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5942 return(NULL);
5943 return((xmlNodePtr)ctxt->context->node->properties);
5944 }
5945 return((xmlNodePtr)cur->next);
5946}
5947
5948/************************************************************************
5949 * *
5950 * NodeTest Functions *
5951 * *
5952 ************************************************************************/
5953
Owen Taylor3473f882001-02-23 17:55:21 +00005954#define IS_FUNCTION 200
5955
Owen Taylor3473f882001-02-23 17:55:21 +00005956
5957/************************************************************************
5958 * *
5959 * Implicit tree core function library *
5960 * *
5961 ************************************************************************/
5962
5963/**
5964 * xmlXPathRoot:
5965 * @ctxt: the XPath Parser context
5966 *
5967 * Initialize the context to the root of the document
5968 */
5969void
5970xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5971 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5972 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5973}
5974
5975/************************************************************************
5976 * *
5977 * The explicit core function library *
5978 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5979 * *
5980 ************************************************************************/
5981
5982
5983/**
5984 * xmlXPathLastFunction:
5985 * @ctxt: the XPath Parser context
5986 * @nargs: the number of arguments
5987 *
5988 * Implement the last() XPath function
5989 * number last()
5990 * The last function returns the number of nodes in the context node list.
5991 */
5992void
5993xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5994 CHECK_ARITY(0);
5995 if (ctxt->context->contextSize >= 0) {
5996 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5997#ifdef DEBUG_EXPR
5998 xmlGenericError(xmlGenericErrorContext,
5999 "last() : %d\n", ctxt->context->contextSize);
6000#endif
6001 } else {
6002 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6003 }
6004}
6005
6006/**
6007 * xmlXPathPositionFunction:
6008 * @ctxt: the XPath Parser context
6009 * @nargs: the number of arguments
6010 *
6011 * Implement the position() XPath function
6012 * number position()
6013 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006014 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00006015 * will be equal to last().
6016 */
6017void
6018xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6019 CHECK_ARITY(0);
6020 if (ctxt->context->proximityPosition >= 0) {
6021 valuePush(ctxt,
6022 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6023#ifdef DEBUG_EXPR
6024 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6025 ctxt->context->proximityPosition);
6026#endif
6027 } else {
6028 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6029 }
6030}
6031
6032/**
6033 * xmlXPathCountFunction:
6034 * @ctxt: the XPath Parser context
6035 * @nargs: the number of arguments
6036 *
6037 * Implement the count() XPath function
6038 * number count(node-set)
6039 */
6040void
6041xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6042 xmlXPathObjectPtr cur;
6043
6044 CHECK_ARITY(1);
6045 if ((ctxt->value == NULL) ||
6046 ((ctxt->value->type != XPATH_NODESET) &&
6047 (ctxt->value->type != XPATH_XSLT_TREE)))
6048 XP_ERROR(XPATH_INVALID_TYPE);
6049 cur = valuePop(ctxt);
6050
Daniel Veillard911f49a2001-04-07 15:39:35 +00006051 if ((cur == NULL) || (cur->nodesetval == NULL))
6052 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006053 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006054 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006055 } else {
6056 if ((cur->nodesetval->nodeNr != 1) ||
6057 (cur->nodesetval->nodeTab == NULL)) {
6058 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6059 } else {
6060 xmlNodePtr tmp;
6061 int i = 0;
6062
6063 tmp = cur->nodesetval->nodeTab[0];
6064 if (tmp != NULL) {
6065 tmp = tmp->children;
6066 while (tmp != NULL) {
6067 tmp = tmp->next;
6068 i++;
6069 }
6070 }
6071 valuePush(ctxt, xmlXPathNewFloat((double) i));
6072 }
6073 }
Owen Taylor3473f882001-02-23 17:55:21 +00006074 xmlXPathFreeObject(cur);
6075}
6076
6077/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006078 * xmlXPathGetElementsByIds:
6079 * @doc: the document
6080 * @ids: a whitespace separated list of IDs
6081 *
6082 * Selects elements by their unique ID.
6083 *
6084 * Returns a node-set of selected elements.
6085 */
6086static xmlNodeSetPtr
6087xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6088 xmlNodeSetPtr ret;
6089 const xmlChar *cur = ids;
6090 xmlChar *ID;
6091 xmlAttrPtr attr;
6092 xmlNodePtr elem = NULL;
6093
Daniel Veillard7a985a12003-07-06 17:57:42 +00006094 if (ids == NULL) return(NULL);
6095
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006096 ret = xmlXPathNodeSetCreate(NULL);
6097
William M. Brack76e95df2003-10-18 16:20:14 +00006098 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006099 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006100 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006101 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006102
6103 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006104 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00006105 /*
6106 * We used to check the fact that the value passed
6107 * was an NCName, but this generated much troubles for
6108 * me and Aleksey Sanin, people blatantly violated that
6109 * constaint, like Visa3D spec.
6110 * if (xmlValidateNCName(ID, 1) == 0)
6111 */
6112 attr = xmlGetID(doc, ID);
6113 if (attr != NULL) {
6114 if (attr->type == XML_ATTRIBUTE_NODE)
6115 elem = attr->parent;
6116 else if (attr->type == XML_ELEMENT_NODE)
6117 elem = (xmlNodePtr) attr;
6118 else
6119 elem = NULL;
6120 if (elem != NULL)
6121 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00006122 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006123 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006124 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006125
William M. Brack76e95df2003-10-18 16:20:14 +00006126 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006127 ids = cur;
6128 }
6129 return(ret);
6130}
6131
6132/**
Owen Taylor3473f882001-02-23 17:55:21 +00006133 * xmlXPathIdFunction:
6134 * @ctxt: the XPath Parser context
6135 * @nargs: the number of arguments
6136 *
6137 * Implement the id() XPath function
6138 * node-set id(object)
6139 * The id function selects elements by their unique ID
6140 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6141 * then the result is the union of the result of applying id to the
6142 * string value of each of the nodes in the argument node-set. When the
6143 * argument to id is of any other type, the argument is converted to a
6144 * string as if by a call to the string function; the string is split
6145 * into a whitespace-separated list of tokens (whitespace is any sequence
6146 * of characters matching the production S); the result is a node-set
6147 * containing the elements in the same document as the context node that
6148 * have a unique ID equal to any of the tokens in the list.
6149 */
6150void
6151xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006152 xmlChar *tokens;
6153 xmlNodeSetPtr ret;
6154 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006155
6156 CHECK_ARITY(1);
6157 obj = valuePop(ctxt);
6158 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006159 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006160 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006161 int i;
6162
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006163 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006164
Daniel Veillard911f49a2001-04-07 15:39:35 +00006165 if (obj->nodesetval != NULL) {
6166 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006167 tokens =
6168 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6169 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6170 ret = xmlXPathNodeSetMerge(ret, ns);
6171 xmlXPathFreeNodeSet(ns);
6172 if (tokens != NULL)
6173 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006174 }
Owen Taylor3473f882001-02-23 17:55:21 +00006175 }
6176
6177 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006178 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006179 return;
6180 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006181 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006182
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006183 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6184 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006185
Owen Taylor3473f882001-02-23 17:55:21 +00006186 xmlXPathFreeObject(obj);
6187 return;
6188}
6189
6190/**
6191 * xmlXPathLocalNameFunction:
6192 * @ctxt: the XPath Parser context
6193 * @nargs: the number of arguments
6194 *
6195 * Implement the local-name() XPath function
6196 * string local-name(node-set?)
6197 * The local-name function returns a string containing the local part
6198 * of the name of the node in the argument node-set that is first in
6199 * document order. If the node-set is empty or the first node has no
6200 * name, an empty string is returned. If the argument is omitted it
6201 * defaults to the context node.
6202 */
6203void
6204xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6205 xmlXPathObjectPtr cur;
6206
6207 if (nargs == 0) {
6208 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6209 nargs = 1;
6210 }
6211
6212 CHECK_ARITY(1);
6213 if ((ctxt->value == NULL) ||
6214 ((ctxt->value->type != XPATH_NODESET) &&
6215 (ctxt->value->type != XPATH_XSLT_TREE)))
6216 XP_ERROR(XPATH_INVALID_TYPE);
6217 cur = valuePop(ctxt);
6218
Daniel Veillard911f49a2001-04-07 15:39:35 +00006219 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006220 valuePush(ctxt, xmlXPathNewCString(""));
6221 } else {
6222 int i = 0; /* Should be first in document order !!!!! */
6223 switch (cur->nodesetval->nodeTab[i]->type) {
6224 case XML_ELEMENT_NODE:
6225 case XML_ATTRIBUTE_NODE:
6226 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006227 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6228 valuePush(ctxt, xmlXPathNewCString(""));
6229 else
6230 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006231 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6232 break;
6233 case XML_NAMESPACE_DECL:
6234 valuePush(ctxt, xmlXPathNewString(
6235 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6236 break;
6237 default:
6238 valuePush(ctxt, xmlXPathNewCString(""));
6239 }
6240 }
6241 xmlXPathFreeObject(cur);
6242}
6243
6244/**
6245 * xmlXPathNamespaceURIFunction:
6246 * @ctxt: the XPath Parser context
6247 * @nargs: the number of arguments
6248 *
6249 * Implement the namespace-uri() XPath function
6250 * string namespace-uri(node-set?)
6251 * The namespace-uri function returns a string containing the
6252 * namespace URI of the expanded name of the node in the argument
6253 * node-set that is first in document order. If the node-set is empty,
6254 * the first node has no name, or the expanded name has no namespace
6255 * URI, an empty string is returned. If the argument is omitted it
6256 * defaults to the context node.
6257 */
6258void
6259xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6260 xmlXPathObjectPtr cur;
6261
6262 if (nargs == 0) {
6263 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6264 nargs = 1;
6265 }
6266 CHECK_ARITY(1);
6267 if ((ctxt->value == NULL) ||
6268 ((ctxt->value->type != XPATH_NODESET) &&
6269 (ctxt->value->type != XPATH_XSLT_TREE)))
6270 XP_ERROR(XPATH_INVALID_TYPE);
6271 cur = valuePop(ctxt);
6272
Daniel Veillard911f49a2001-04-07 15:39:35 +00006273 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006274 valuePush(ctxt, xmlXPathNewCString(""));
6275 } else {
6276 int i = 0; /* Should be first in document order !!!!! */
6277 switch (cur->nodesetval->nodeTab[i]->type) {
6278 case XML_ELEMENT_NODE:
6279 case XML_ATTRIBUTE_NODE:
6280 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6281 valuePush(ctxt, xmlXPathNewCString(""));
6282 else
6283 valuePush(ctxt, xmlXPathNewString(
6284 cur->nodesetval->nodeTab[i]->ns->href));
6285 break;
6286 default:
6287 valuePush(ctxt, xmlXPathNewCString(""));
6288 }
6289 }
6290 xmlXPathFreeObject(cur);
6291}
6292
6293/**
6294 * xmlXPathNameFunction:
6295 * @ctxt: the XPath Parser context
6296 * @nargs: the number of arguments
6297 *
6298 * Implement the name() XPath function
6299 * string name(node-set?)
6300 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006301 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006302 * order. The QName must represent the name with respect to the namespace
6303 * declarations in effect on the node whose name is being represented.
6304 * Typically, this will be the form in which the name occurred in the XML
6305 * source. This need not be the case if there are namespace declarations
6306 * in effect on the node that associate multiple prefixes with the same
6307 * namespace. However, an implementation may include information about
6308 * the original prefix in its representation of nodes; in this case, an
6309 * implementation can ensure that the returned string is always the same
6310 * as the QName used in the XML source. If the argument it omitted it
6311 * defaults to the context node.
6312 * Libxml keep the original prefix so the "real qualified name" used is
6313 * returned.
6314 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006315static void
Daniel Veillard04383752001-07-08 14:27:15 +00006316xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6317{
Owen Taylor3473f882001-02-23 17:55:21 +00006318 xmlXPathObjectPtr cur;
6319
6320 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006321 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6322 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006323 }
6324
6325 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006326 if ((ctxt->value == NULL) ||
6327 ((ctxt->value->type != XPATH_NODESET) &&
6328 (ctxt->value->type != XPATH_XSLT_TREE)))
6329 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006330 cur = valuePop(ctxt);
6331
Daniel Veillard911f49a2001-04-07 15:39:35 +00006332 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006333 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006334 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006335 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006336
Daniel Veillard04383752001-07-08 14:27:15 +00006337 switch (cur->nodesetval->nodeTab[i]->type) {
6338 case XML_ELEMENT_NODE:
6339 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006340 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6341 valuePush(ctxt, xmlXPathNewCString(""));
6342 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6343 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006344 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006345 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006346
Daniel Veillard652d8a92003-02-04 19:28:49 +00006347 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006348 xmlChar *fullname;
6349
6350 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6351 cur->nodesetval->nodeTab[i]->ns->prefix,
6352 NULL, 0);
6353 if (fullname == cur->nodesetval->nodeTab[i]->name)
6354 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6355 if (fullname == NULL) {
6356 XP_ERROR(XPATH_MEMORY_ERROR);
6357 }
6358 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006359 }
6360 break;
6361 default:
6362 valuePush(ctxt,
6363 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6364 xmlXPathLocalNameFunction(ctxt, 1);
6365 }
Owen Taylor3473f882001-02-23 17:55:21 +00006366 }
6367 xmlXPathFreeObject(cur);
6368}
6369
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006370
6371/**
Owen Taylor3473f882001-02-23 17:55:21 +00006372 * xmlXPathStringFunction:
6373 * @ctxt: the XPath Parser context
6374 * @nargs: the number of arguments
6375 *
6376 * Implement the string() XPath function
6377 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006378 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006379 * - A node-set is converted to a string by returning the value of
6380 * the node in the node-set that is first in document order.
6381 * If the node-set is empty, an empty string is returned.
6382 * - A number is converted to a string as follows
6383 * + NaN is converted to the string NaN
6384 * + positive zero is converted to the string 0
6385 * + negative zero is converted to the string 0
6386 * + positive infinity is converted to the string Infinity
6387 * + negative infinity is converted to the string -Infinity
6388 * + if the number is an integer, the number is represented in
6389 * decimal form as a Number with no decimal point and no leading
6390 * zeros, preceded by a minus sign (-) if the number is negative
6391 * + otherwise, the number is represented in decimal form as a
6392 * Number including a decimal point with at least one digit
6393 * before the decimal point and at least one digit after the
6394 * decimal point, preceded by a minus sign (-) if the number
6395 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006396 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006397 * before the decimal point; beyond the one required digit
6398 * after the decimal point there must be as many, but only as
6399 * many, more digits as are needed to uniquely distinguish the
6400 * number from all other IEEE 754 numeric values.
6401 * - The boolean false value is converted to the string false.
6402 * The boolean true value is converted to the string true.
6403 *
6404 * If the argument is omitted, it defaults to a node-set with the
6405 * context node as its only member.
6406 */
6407void
6408xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6409 xmlXPathObjectPtr cur;
6410
6411 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006412 valuePush(ctxt,
6413 xmlXPathWrapString(
6414 xmlXPathCastNodeToString(ctxt->context->node)));
6415 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006416 }
6417
6418 CHECK_ARITY(1);
6419 cur = valuePop(ctxt);
6420 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006421 cur = xmlXPathConvertString(cur);
6422 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006423}
6424
6425/**
6426 * xmlXPathStringLengthFunction:
6427 * @ctxt: the XPath Parser context
6428 * @nargs: the number of arguments
6429 *
6430 * Implement the string-length() XPath function
6431 * number string-length(string?)
6432 * The string-length returns the number of characters in the string
6433 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6434 * the context node converted to a string, in other words the value
6435 * of the context node.
6436 */
6437void
6438xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6439 xmlXPathObjectPtr cur;
6440
6441 if (nargs == 0) {
6442 if (ctxt->context->node == NULL) {
6443 valuePush(ctxt, xmlXPathNewFloat(0));
6444 } else {
6445 xmlChar *content;
6446
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006447 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006448 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006449 xmlFree(content);
6450 }
6451 return;
6452 }
6453 CHECK_ARITY(1);
6454 CAST_TO_STRING;
6455 CHECK_TYPE(XPATH_STRING);
6456 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006457 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006458 xmlXPathFreeObject(cur);
6459}
6460
6461/**
6462 * xmlXPathConcatFunction:
6463 * @ctxt: the XPath Parser context
6464 * @nargs: the number of arguments
6465 *
6466 * Implement the concat() XPath function
6467 * string concat(string, string, string*)
6468 * The concat function returns the concatenation of its arguments.
6469 */
6470void
6471xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6472 xmlXPathObjectPtr cur, newobj;
6473 xmlChar *tmp;
6474
6475 if (nargs < 2) {
6476 CHECK_ARITY(2);
6477 }
6478
6479 CAST_TO_STRING;
6480 cur = valuePop(ctxt);
6481 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6482 xmlXPathFreeObject(cur);
6483 return;
6484 }
6485 nargs--;
6486
6487 while (nargs > 0) {
6488 CAST_TO_STRING;
6489 newobj = valuePop(ctxt);
6490 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6491 xmlXPathFreeObject(newobj);
6492 xmlXPathFreeObject(cur);
6493 XP_ERROR(XPATH_INVALID_TYPE);
6494 }
6495 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6496 newobj->stringval = cur->stringval;
6497 cur->stringval = tmp;
6498
6499 xmlXPathFreeObject(newobj);
6500 nargs--;
6501 }
6502 valuePush(ctxt, cur);
6503}
6504
6505/**
6506 * xmlXPathContainsFunction:
6507 * @ctxt: the XPath Parser context
6508 * @nargs: the number of arguments
6509 *
6510 * Implement the contains() XPath function
6511 * boolean contains(string, string)
6512 * The contains function returns true if the first argument string
6513 * contains the second argument string, and otherwise returns false.
6514 */
6515void
6516xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6517 xmlXPathObjectPtr hay, needle;
6518
6519 CHECK_ARITY(2);
6520 CAST_TO_STRING;
6521 CHECK_TYPE(XPATH_STRING);
6522 needle = valuePop(ctxt);
6523 CAST_TO_STRING;
6524 hay = valuePop(ctxt);
6525 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6526 xmlXPathFreeObject(hay);
6527 xmlXPathFreeObject(needle);
6528 XP_ERROR(XPATH_INVALID_TYPE);
6529 }
6530 if (xmlStrstr(hay->stringval, needle->stringval))
6531 valuePush(ctxt, xmlXPathNewBoolean(1));
6532 else
6533 valuePush(ctxt, xmlXPathNewBoolean(0));
6534 xmlXPathFreeObject(hay);
6535 xmlXPathFreeObject(needle);
6536}
6537
6538/**
6539 * xmlXPathStartsWithFunction:
6540 * @ctxt: the XPath Parser context
6541 * @nargs: the number of arguments
6542 *
6543 * Implement the starts-with() XPath function
6544 * boolean starts-with(string, string)
6545 * The starts-with function returns true if the first argument string
6546 * starts with the second argument string, and otherwise returns false.
6547 */
6548void
6549xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6550 xmlXPathObjectPtr hay, needle;
6551 int n;
6552
6553 CHECK_ARITY(2);
6554 CAST_TO_STRING;
6555 CHECK_TYPE(XPATH_STRING);
6556 needle = valuePop(ctxt);
6557 CAST_TO_STRING;
6558 hay = valuePop(ctxt);
6559 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6560 xmlXPathFreeObject(hay);
6561 xmlXPathFreeObject(needle);
6562 XP_ERROR(XPATH_INVALID_TYPE);
6563 }
6564 n = xmlStrlen(needle->stringval);
6565 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6566 valuePush(ctxt, xmlXPathNewBoolean(0));
6567 else
6568 valuePush(ctxt, xmlXPathNewBoolean(1));
6569 xmlXPathFreeObject(hay);
6570 xmlXPathFreeObject(needle);
6571}
6572
6573/**
6574 * xmlXPathSubstringFunction:
6575 * @ctxt: the XPath Parser context
6576 * @nargs: the number of arguments
6577 *
6578 * Implement the substring() XPath function
6579 * string substring(string, number, number?)
6580 * The substring function returns the substring of the first argument
6581 * starting at the position specified in the second argument with
6582 * length specified in the third argument. For example,
6583 * substring("12345",2,3) returns "234". If the third argument is not
6584 * specified, it returns the substring starting at the position specified
6585 * in the second argument and continuing to the end of the string. For
6586 * example, substring("12345",2) returns "2345". More precisely, each
6587 * character in the string (see [3.6 Strings]) is considered to have a
6588 * numeric position: the position of the first character is 1, the position
6589 * of the second character is 2 and so on. The returned substring contains
6590 * those characters for which the position of the character is greater than
6591 * or equal to the second argument and, if the third argument is specified,
6592 * less than the sum of the second and third arguments; the comparisons
6593 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6594 * - substring("12345", 1.5, 2.6) returns "234"
6595 * - substring("12345", 0, 3) returns "12"
6596 * - substring("12345", 0 div 0, 3) returns ""
6597 * - substring("12345", 1, 0 div 0) returns ""
6598 * - substring("12345", -42, 1 div 0) returns "12345"
6599 * - substring("12345", -1 div 0, 1 div 0) returns ""
6600 */
6601void
6602xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6603 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006604 double le=0, in;
6605 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006606 xmlChar *ret;
6607
Owen Taylor3473f882001-02-23 17:55:21 +00006608 if (nargs < 2) {
6609 CHECK_ARITY(2);
6610 }
6611 if (nargs > 3) {
6612 CHECK_ARITY(3);
6613 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006614 /*
6615 * take care of possible last (position) argument
6616 */
Owen Taylor3473f882001-02-23 17:55:21 +00006617 if (nargs == 3) {
6618 CAST_TO_NUMBER;
6619 CHECK_TYPE(XPATH_NUMBER);
6620 len = valuePop(ctxt);
6621 le = len->floatval;
6622 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006623 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006624
Owen Taylor3473f882001-02-23 17:55:21 +00006625 CAST_TO_NUMBER;
6626 CHECK_TYPE(XPATH_NUMBER);
6627 start = valuePop(ctxt);
6628 in = start->floatval;
6629 xmlXPathFreeObject(start);
6630 CAST_TO_STRING;
6631 CHECK_TYPE(XPATH_STRING);
6632 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006633 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006634
Daniel Veillard97ac1312001-05-30 19:14:17 +00006635 /*
6636 * If last pos not present, calculate last position
6637 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006638 if (nargs != 3) {
6639 le = (double)m;
6640 if (in < 1.0)
6641 in = 1.0;
6642 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006643
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006644 /* Need to check for the special cases where either
6645 * the index is NaN, the length is NaN, or both
6646 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006647 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006648 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006649 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006650 * To meet the requirements of the spec, the arguments
6651 * must be converted to integer format before
6652 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006653 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006654 * First we go to integer form, rounding up
6655 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006656 */
6657 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006658 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006659
Daniel Veillard9e412302002-06-10 15:59:44 +00006660 if (xmlXPathIsInf(le) == 1) {
6661 l = m;
6662 if (i < 1)
6663 i = 1;
6664 }
6665 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6666 l = 0;
6667 else {
6668 l = (int) le;
6669 if (((double)l)+0.5 <= le) l++;
6670 }
6671
6672 /* Now we normalize inidices */
6673 i -= 1;
6674 l += i;
6675 if (i < 0)
6676 i = 0;
6677 if (l > m)
6678 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006679
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006680 /* number of chars to copy */
6681 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006682
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006683 ret = xmlUTF8Strsub(str->stringval, i, l);
6684 }
6685 else {
6686 ret = NULL;
6687 }
6688
Owen Taylor3473f882001-02-23 17:55:21 +00006689 if (ret == NULL)
6690 valuePush(ctxt, xmlXPathNewCString(""));
6691 else {
6692 valuePush(ctxt, xmlXPathNewString(ret));
6693 xmlFree(ret);
6694 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006695
Owen Taylor3473f882001-02-23 17:55:21 +00006696 xmlXPathFreeObject(str);
6697}
6698
6699/**
6700 * xmlXPathSubstringBeforeFunction:
6701 * @ctxt: the XPath Parser context
6702 * @nargs: the number of arguments
6703 *
6704 * Implement the substring-before() XPath function
6705 * string substring-before(string, string)
6706 * The substring-before function returns the substring of the first
6707 * argument string that precedes the first occurrence of the second
6708 * argument string in the first argument string, or the empty string
6709 * if the first argument string does not contain the second argument
6710 * string. For example, substring-before("1999/04/01","/") returns 1999.
6711 */
6712void
6713xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6714 xmlXPathObjectPtr str;
6715 xmlXPathObjectPtr find;
6716 xmlBufferPtr target;
6717 const xmlChar *point;
6718 int offset;
6719
6720 CHECK_ARITY(2);
6721 CAST_TO_STRING;
6722 find = valuePop(ctxt);
6723 CAST_TO_STRING;
6724 str = valuePop(ctxt);
6725
6726 target = xmlBufferCreate();
6727 if (target) {
6728 point = xmlStrstr(str->stringval, find->stringval);
6729 if (point) {
6730 offset = (int)(point - str->stringval);
6731 xmlBufferAdd(target, str->stringval, offset);
6732 }
6733 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6734 xmlBufferFree(target);
6735 }
6736
6737 xmlXPathFreeObject(str);
6738 xmlXPathFreeObject(find);
6739}
6740
6741/**
6742 * xmlXPathSubstringAfterFunction:
6743 * @ctxt: the XPath Parser context
6744 * @nargs: the number of arguments
6745 *
6746 * Implement the substring-after() XPath function
6747 * string substring-after(string, string)
6748 * The substring-after function returns the substring of the first
6749 * argument string that follows the first occurrence of the second
6750 * argument string in the first argument string, or the empty stringi
6751 * if the first argument string does not contain the second argument
6752 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6753 * and substring-after("1999/04/01","19") returns 99/04/01.
6754 */
6755void
6756xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6757 xmlXPathObjectPtr str;
6758 xmlXPathObjectPtr find;
6759 xmlBufferPtr target;
6760 const xmlChar *point;
6761 int offset;
6762
6763 CHECK_ARITY(2);
6764 CAST_TO_STRING;
6765 find = valuePop(ctxt);
6766 CAST_TO_STRING;
6767 str = valuePop(ctxt);
6768
6769 target = xmlBufferCreate();
6770 if (target) {
6771 point = xmlStrstr(str->stringval, find->stringval);
6772 if (point) {
6773 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6774 xmlBufferAdd(target, &str->stringval[offset],
6775 xmlStrlen(str->stringval) - offset);
6776 }
6777 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6778 xmlBufferFree(target);
6779 }
6780
6781 xmlXPathFreeObject(str);
6782 xmlXPathFreeObject(find);
6783}
6784
6785/**
6786 * xmlXPathNormalizeFunction:
6787 * @ctxt: the XPath Parser context
6788 * @nargs: the number of arguments
6789 *
6790 * Implement the normalize-space() XPath function
6791 * string normalize-space(string?)
6792 * The normalize-space function returns the argument string with white
6793 * space normalized by stripping leading and trailing whitespace
6794 * and replacing sequences of whitespace characters by a single
6795 * space. Whitespace characters are the same allowed by the S production
6796 * in XML. If the argument is omitted, it defaults to the context
6797 * node converted to a string, in other words the value of the context node.
6798 */
6799void
6800xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6801 xmlXPathObjectPtr obj = NULL;
6802 xmlChar *source = NULL;
6803 xmlBufferPtr target;
6804 xmlChar blank;
6805
6806 if (nargs == 0) {
6807 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006808 valuePush(ctxt,
6809 xmlXPathWrapString(
6810 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006811 nargs = 1;
6812 }
6813
6814 CHECK_ARITY(1);
6815 CAST_TO_STRING;
6816 CHECK_TYPE(XPATH_STRING);
6817 obj = valuePop(ctxt);
6818 source = obj->stringval;
6819
6820 target = xmlBufferCreate();
6821 if (target && source) {
6822
6823 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006824 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006825 source++;
6826
6827 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6828 blank = 0;
6829 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006830 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006831 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006832 } else {
6833 if (blank) {
6834 xmlBufferAdd(target, &blank, 1);
6835 blank = 0;
6836 }
6837 xmlBufferAdd(target, source, 1);
6838 }
6839 source++;
6840 }
6841
6842 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6843 xmlBufferFree(target);
6844 }
6845 xmlXPathFreeObject(obj);
6846}
6847
6848/**
6849 * xmlXPathTranslateFunction:
6850 * @ctxt: the XPath Parser context
6851 * @nargs: the number of arguments
6852 *
6853 * Implement the translate() XPath function
6854 * string translate(string, string, string)
6855 * The translate function returns the first argument string with
6856 * occurrences of characters in the second argument string replaced
6857 * by the character at the corresponding position in the third argument
6858 * string. For example, translate("bar","abc","ABC") returns the string
6859 * BAr. If there is a character in the second argument string with no
6860 * character at a corresponding position in the third argument string
6861 * (because the second argument string is longer than the third argument
6862 * string), then occurrences of that character in the first argument
6863 * string are removed. For example, translate("--aaa--","abc-","ABC")
6864 * returns "AAA". If a character occurs more than once in second
6865 * argument string, then the first occurrence determines the replacement
6866 * character. If the third argument string is longer than the second
6867 * argument string, then excess characters are ignored.
6868 */
6869void
6870xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006871 xmlXPathObjectPtr str;
6872 xmlXPathObjectPtr from;
6873 xmlXPathObjectPtr to;
6874 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006875 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006876 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006877 xmlChar *point;
6878 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006879
Daniel Veillarde043ee12001-04-16 14:08:07 +00006880 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006881
Daniel Veillarde043ee12001-04-16 14:08:07 +00006882 CAST_TO_STRING;
6883 to = valuePop(ctxt);
6884 CAST_TO_STRING;
6885 from = valuePop(ctxt);
6886 CAST_TO_STRING;
6887 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006888
Daniel Veillarde043ee12001-04-16 14:08:07 +00006889 target = xmlBufferCreate();
6890 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006891 max = xmlUTF8Strlen(to->stringval);
6892 for (cptr = str->stringval; (ch=*cptr); ) {
6893 offset = xmlUTF8Strloc(from->stringval, cptr);
6894 if (offset >= 0) {
6895 if (offset < max) {
6896 point = xmlUTF8Strpos(to->stringval, offset);
6897 if (point)
6898 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6899 }
6900 } else
6901 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6902
6903 /* Step to next character in input */
6904 cptr++;
6905 if ( ch & 0x80 ) {
6906 /* if not simple ascii, verify proper format */
6907 if ( (ch & 0xc0) != 0xc0 ) {
6908 xmlGenericError(xmlGenericErrorContext,
6909 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6910 break;
6911 }
6912 /* then skip over remaining bytes for this char */
6913 while ( (ch <<= 1) & 0x80 )
6914 if ( (*cptr++ & 0xc0) != 0x80 ) {
6915 xmlGenericError(xmlGenericErrorContext,
6916 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6917 break;
6918 }
6919 if (ch & 0x80) /* must have had error encountered */
6920 break;
6921 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006922 }
Owen Taylor3473f882001-02-23 17:55:21 +00006923 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006924 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6925 xmlBufferFree(target);
6926 xmlXPathFreeObject(str);
6927 xmlXPathFreeObject(from);
6928 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006929}
6930
6931/**
6932 * xmlXPathBooleanFunction:
6933 * @ctxt: the XPath Parser context
6934 * @nargs: the number of arguments
6935 *
6936 * Implement the boolean() XPath function
6937 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00006938 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006939 * - a number is true if and only if it is neither positive or
6940 * negative zero nor NaN
6941 * - a node-set is true if and only if it is non-empty
6942 * - a string is true if and only if its length is non-zero
6943 */
6944void
6945xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6946 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006947
6948 CHECK_ARITY(1);
6949 cur = valuePop(ctxt);
6950 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006951 cur = xmlXPathConvertBoolean(cur);
6952 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006953}
6954
6955/**
6956 * xmlXPathNotFunction:
6957 * @ctxt: the XPath Parser context
6958 * @nargs: the number of arguments
6959 *
6960 * Implement the not() XPath function
6961 * boolean not(boolean)
6962 * The not function returns true if its argument is false,
6963 * and false otherwise.
6964 */
6965void
6966xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6967 CHECK_ARITY(1);
6968 CAST_TO_BOOLEAN;
6969 CHECK_TYPE(XPATH_BOOLEAN);
6970 ctxt->value->boolval = ! ctxt->value->boolval;
6971}
6972
6973/**
6974 * xmlXPathTrueFunction:
6975 * @ctxt: the XPath Parser context
6976 * @nargs: the number of arguments
6977 *
6978 * Implement the true() XPath function
6979 * boolean true()
6980 */
6981void
6982xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6983 CHECK_ARITY(0);
6984 valuePush(ctxt, xmlXPathNewBoolean(1));
6985}
6986
6987/**
6988 * xmlXPathFalseFunction:
6989 * @ctxt: the XPath Parser context
6990 * @nargs: the number of arguments
6991 *
6992 * Implement the false() XPath function
6993 * boolean false()
6994 */
6995void
6996xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6997 CHECK_ARITY(0);
6998 valuePush(ctxt, xmlXPathNewBoolean(0));
6999}
7000
7001/**
7002 * xmlXPathLangFunction:
7003 * @ctxt: the XPath Parser context
7004 * @nargs: the number of arguments
7005 *
7006 * Implement the lang() XPath function
7007 * boolean lang(string)
7008 * The lang function returns true or false depending on whether the
7009 * language of the context node as specified by xml:lang attributes
7010 * is the same as or is a sublanguage of the language specified by
7011 * the argument string. The language of the context node is determined
7012 * by the value of the xml:lang attribute on the context node, or, if
7013 * the context node has no xml:lang attribute, by the value of the
7014 * xml:lang attribute on the nearest ancestor of the context node that
7015 * has an xml:lang attribute. If there is no such attribute, then lang
7016 * returns false. If there is such an attribute, then lang returns
7017 * true if the attribute value is equal to the argument ignoring case,
7018 * or if there is some suffix starting with - such that the attribute
7019 * value is equal to the argument ignoring that suffix of the attribute
7020 * value and ignoring case.
7021 */
7022void
7023xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7024 xmlXPathObjectPtr val;
7025 const xmlChar *theLang;
7026 const xmlChar *lang;
7027 int ret = 0;
7028 int i;
7029
7030 CHECK_ARITY(1);
7031 CAST_TO_STRING;
7032 CHECK_TYPE(XPATH_STRING);
7033 val = valuePop(ctxt);
7034 lang = val->stringval;
7035 theLang = xmlNodeGetLang(ctxt->context->node);
7036 if ((theLang != NULL) && (lang != NULL)) {
7037 for (i = 0;lang[i] != 0;i++)
7038 if (toupper(lang[i]) != toupper(theLang[i]))
7039 goto not_equal;
7040 ret = 1;
7041 }
7042not_equal:
William M. Bracka59ddb52004-02-25 08:12:32 +00007043 xmlFree((void *)theLang);
Owen Taylor3473f882001-02-23 17:55:21 +00007044 xmlXPathFreeObject(val);
7045 valuePush(ctxt, xmlXPathNewBoolean(ret));
7046}
7047
7048/**
7049 * xmlXPathNumberFunction:
7050 * @ctxt: the XPath Parser context
7051 * @nargs: the number of arguments
7052 *
7053 * Implement the number() XPath function
7054 * number number(object?)
7055 */
7056void
7057xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7058 xmlXPathObjectPtr cur;
7059 double res;
7060
7061 if (nargs == 0) {
7062 if (ctxt->context->node == NULL) {
7063 valuePush(ctxt, xmlXPathNewFloat(0.0));
7064 } else {
7065 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7066
7067 res = xmlXPathStringEvalNumber(content);
7068 valuePush(ctxt, xmlXPathNewFloat(res));
7069 xmlFree(content);
7070 }
7071 return;
7072 }
7073
7074 CHECK_ARITY(1);
7075 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007076 cur = xmlXPathConvertNumber(cur);
7077 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007078}
7079
7080/**
7081 * xmlXPathSumFunction:
7082 * @ctxt: the XPath Parser context
7083 * @nargs: the number of arguments
7084 *
7085 * Implement the sum() XPath function
7086 * number sum(node-set)
7087 * The sum function returns the sum of the values of the nodes in
7088 * the argument node-set.
7089 */
7090void
7091xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7092 xmlXPathObjectPtr cur;
7093 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007094 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007095
7096 CHECK_ARITY(1);
7097 if ((ctxt->value == NULL) ||
7098 ((ctxt->value->type != XPATH_NODESET) &&
7099 (ctxt->value->type != XPATH_XSLT_TREE)))
7100 XP_ERROR(XPATH_INVALID_TYPE);
7101 cur = valuePop(ctxt);
7102
William M. Brack08171912003-12-29 02:52:11 +00007103 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007104 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7105 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007106 }
7107 }
William M. Brack08171912003-12-29 02:52:11 +00007108 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007109 xmlXPathFreeObject(cur);
7110}
7111
7112/**
7113 * xmlXPathFloorFunction:
7114 * @ctxt: the XPath Parser context
7115 * @nargs: the number of arguments
7116 *
7117 * Implement the floor() XPath function
7118 * number floor(number)
7119 * The floor function returns the largest (closest to positive infinity)
7120 * number that is not greater than the argument and that is an integer.
7121 */
7122void
7123xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007124 double f;
7125
Owen Taylor3473f882001-02-23 17:55:21 +00007126 CHECK_ARITY(1);
7127 CAST_TO_NUMBER;
7128 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007129
7130 f = (double)((int) ctxt->value->floatval);
7131 if (f != ctxt->value->floatval) {
7132 if (ctxt->value->floatval > 0)
7133 ctxt->value->floatval = f;
7134 else
7135 ctxt->value->floatval = f - 1;
7136 }
Owen Taylor3473f882001-02-23 17:55:21 +00007137}
7138
7139/**
7140 * xmlXPathCeilingFunction:
7141 * @ctxt: the XPath Parser context
7142 * @nargs: the number of arguments
7143 *
7144 * Implement the ceiling() XPath function
7145 * number ceiling(number)
7146 * The ceiling function returns the smallest (closest to negative infinity)
7147 * number that is not less than the argument and that is an integer.
7148 */
7149void
7150xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7151 double f;
7152
7153 CHECK_ARITY(1);
7154 CAST_TO_NUMBER;
7155 CHECK_TYPE(XPATH_NUMBER);
7156
7157#if 0
7158 ctxt->value->floatval = ceil(ctxt->value->floatval);
7159#else
7160 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007161 if (f != ctxt->value->floatval) {
7162 if (ctxt->value->floatval > 0)
7163 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007164 else {
7165 if (ctxt->value->floatval < 0 && f == 0)
7166 ctxt->value->floatval = xmlXPathNZERO;
7167 else
7168 ctxt->value->floatval = f;
7169 }
7170
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007171 }
Owen Taylor3473f882001-02-23 17:55:21 +00007172#endif
7173}
7174
7175/**
7176 * xmlXPathRoundFunction:
7177 * @ctxt: the XPath Parser context
7178 * @nargs: the number of arguments
7179 *
7180 * Implement the round() XPath function
7181 * number round(number)
7182 * The round function returns the number that is closest to the
7183 * argument and that is an integer. If there are two such numbers,
7184 * then the one that is even is returned.
7185 */
7186void
7187xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7188 double f;
7189
7190 CHECK_ARITY(1);
7191 CAST_TO_NUMBER;
7192 CHECK_TYPE(XPATH_NUMBER);
7193
Daniel Veillardcda96922001-08-21 10:56:31 +00007194 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7195 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7196 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007197 (ctxt->value->floatval == 0.0))
7198 return;
7199
Owen Taylor3473f882001-02-23 17:55:21 +00007200 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007201 if (ctxt->value->floatval < 0) {
7202 if (ctxt->value->floatval < f - 0.5)
7203 ctxt->value->floatval = f - 1;
7204 else
7205 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007206 if (ctxt->value->floatval == 0)
7207 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007208 } else {
7209 if (ctxt->value->floatval < f + 0.5)
7210 ctxt->value->floatval = f;
7211 else
7212 ctxt->value->floatval = f + 1;
7213 }
Owen Taylor3473f882001-02-23 17:55:21 +00007214}
7215
7216/************************************************************************
7217 * *
7218 * The Parser *
7219 * *
7220 ************************************************************************/
7221
7222/*
William M. Brack08171912003-12-29 02:52:11 +00007223 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007224 * implementation.
7225 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007226static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007227static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007228static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007229static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007230static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7231 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007232
7233/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007234 * xmlXPathCurrentChar:
7235 * @ctxt: the XPath parser context
7236 * @cur: pointer to the beginning of the char
7237 * @len: pointer to the length of the char read
7238 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007239 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007240 * bytes in the input buffer.
7241 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007242 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007243 */
7244
7245static int
7246xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7247 unsigned char c;
7248 unsigned int val;
7249 const xmlChar *cur;
7250
7251 if (ctxt == NULL)
7252 return(0);
7253 cur = ctxt->cur;
7254
7255 /*
7256 * We are supposed to handle UTF8, check it's valid
7257 * From rfc2044: encoding of the Unicode values on UTF-8:
7258 *
7259 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7260 * 0000 0000-0000 007F 0xxxxxxx
7261 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7262 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7263 *
7264 * Check for the 0x110000 limit too
7265 */
7266 c = *cur;
7267 if (c & 0x80) {
7268 if ((cur[1] & 0xc0) != 0x80)
7269 goto encoding_error;
7270 if ((c & 0xe0) == 0xe0) {
7271
7272 if ((cur[2] & 0xc0) != 0x80)
7273 goto encoding_error;
7274 if ((c & 0xf0) == 0xf0) {
7275 if (((c & 0xf8) != 0xf0) ||
7276 ((cur[3] & 0xc0) != 0x80))
7277 goto encoding_error;
7278 /* 4-byte code */
7279 *len = 4;
7280 val = (cur[0] & 0x7) << 18;
7281 val |= (cur[1] & 0x3f) << 12;
7282 val |= (cur[2] & 0x3f) << 6;
7283 val |= cur[3] & 0x3f;
7284 } else {
7285 /* 3-byte code */
7286 *len = 3;
7287 val = (cur[0] & 0xf) << 12;
7288 val |= (cur[1] & 0x3f) << 6;
7289 val |= cur[2] & 0x3f;
7290 }
7291 } else {
7292 /* 2-byte code */
7293 *len = 2;
7294 val = (cur[0] & 0x1f) << 6;
7295 val |= cur[1] & 0x3f;
7296 }
7297 if (!IS_CHAR(val)) {
7298 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7299 }
7300 return(val);
7301 } else {
7302 /* 1-byte code */
7303 *len = 1;
7304 return((int) *cur);
7305 }
7306encoding_error:
7307 /*
William M. Brack08171912003-12-29 02:52:11 +00007308 * If we detect an UTF8 error that probably means that the
7309 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007310 * declaration header. Report the error and switch the encoding
7311 * to ISO-Latin-1 (if you don't like this policy, just declare the
7312 * encoding !)
7313 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007314 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007315 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007316}
7317
7318/**
Owen Taylor3473f882001-02-23 17:55:21 +00007319 * xmlXPathParseNCName:
7320 * @ctxt: the XPath Parser context
7321 *
7322 * parse an XML namespace non qualified name.
7323 *
7324 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7325 *
7326 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7327 * CombiningChar | Extender
7328 *
7329 * Returns the namespace name or NULL
7330 */
7331
7332xmlChar *
7333xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007334 const xmlChar *in;
7335 xmlChar *ret;
7336 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007337
Daniel Veillard2156a562001-04-28 12:24:34 +00007338 /*
7339 * Accelerator for simple ASCII names
7340 */
7341 in = ctxt->cur;
7342 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7343 ((*in >= 0x41) && (*in <= 0x5A)) ||
7344 (*in == '_')) {
7345 in++;
7346 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7347 ((*in >= 0x41) && (*in <= 0x5A)) ||
7348 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007349 (*in == '_') || (*in == '.') ||
7350 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007351 in++;
7352 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7353 (*in == '[') || (*in == ']') || (*in == ':') ||
7354 (*in == '@') || (*in == '*')) {
7355 count = in - ctxt->cur;
7356 if (count == 0)
7357 return(NULL);
7358 ret = xmlStrndup(ctxt->cur, count);
7359 ctxt->cur = in;
7360 return(ret);
7361 }
7362 }
7363 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007364}
7365
Daniel Veillard2156a562001-04-28 12:24:34 +00007366
Owen Taylor3473f882001-02-23 17:55:21 +00007367/**
7368 * xmlXPathParseQName:
7369 * @ctxt: the XPath Parser context
7370 * @prefix: a xmlChar **
7371 *
7372 * parse an XML qualified name
7373 *
7374 * [NS 5] QName ::= (Prefix ':')? LocalPart
7375 *
7376 * [NS 6] Prefix ::= NCName
7377 *
7378 * [NS 7] LocalPart ::= NCName
7379 *
7380 * Returns the function returns the local part, and prefix is updated
7381 * to get the Prefix if any.
7382 */
7383
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007384static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007385xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7386 xmlChar *ret = NULL;
7387
7388 *prefix = NULL;
7389 ret = xmlXPathParseNCName(ctxt);
7390 if (CUR == ':') {
7391 *prefix = ret;
7392 NEXT;
7393 ret = xmlXPathParseNCName(ctxt);
7394 }
7395 return(ret);
7396}
7397
7398/**
7399 * xmlXPathParseName:
7400 * @ctxt: the XPath Parser context
7401 *
7402 * parse an XML name
7403 *
7404 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7405 * CombiningChar | Extender
7406 *
7407 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7408 *
7409 * Returns the namespace name or NULL
7410 */
7411
7412xmlChar *
7413xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007414 const xmlChar *in;
7415 xmlChar *ret;
7416 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007417
Daniel Veillard61d80a22001-04-27 17:13:01 +00007418 /*
7419 * Accelerator for simple ASCII names
7420 */
7421 in = ctxt->cur;
7422 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7423 ((*in >= 0x41) && (*in <= 0x5A)) ||
7424 (*in == '_') || (*in == ':')) {
7425 in++;
7426 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7427 ((*in >= 0x41) && (*in <= 0x5A)) ||
7428 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007429 (*in == '_') || (*in == '-') ||
7430 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007431 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007432 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007433 count = in - ctxt->cur;
7434 ret = xmlStrndup(ctxt->cur, count);
7435 ctxt->cur = in;
7436 return(ret);
7437 }
7438 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007439 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007440}
7441
Daniel Veillard61d80a22001-04-27 17:13:01 +00007442static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007443xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007444 xmlChar buf[XML_MAX_NAMELEN + 5];
7445 int len = 0, l;
7446 int c;
7447
7448 /*
7449 * Handler for more complex cases
7450 */
7451 c = CUR_CHAR(l);
7452 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007453 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7454 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007455 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007456 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007457 return(NULL);
7458 }
7459
7460 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7461 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7462 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007463 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007464 (IS_COMBINING(c)) ||
7465 (IS_EXTENDER(c)))) {
7466 COPY_BUF(l,buf,len,c);
7467 NEXTL(l);
7468 c = CUR_CHAR(l);
7469 if (len >= XML_MAX_NAMELEN) {
7470 /*
7471 * Okay someone managed to make a huge name, so he's ready to pay
7472 * for the processing speed.
7473 */
7474 xmlChar *buffer;
7475 int max = len * 2;
7476
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007477 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007478 if (buffer == NULL) {
7479 XP_ERROR0(XPATH_MEMORY_ERROR);
7480 }
7481 memcpy(buffer, buf, len);
7482 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7483 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007484 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007485 (IS_COMBINING(c)) ||
7486 (IS_EXTENDER(c))) {
7487 if (len + 10 > max) {
7488 max *= 2;
7489 buffer = (xmlChar *) xmlRealloc(buffer,
7490 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007491 if (buffer == NULL) {
7492 XP_ERROR0(XPATH_MEMORY_ERROR);
7493 }
7494 }
7495 COPY_BUF(l,buffer,len,c);
7496 NEXTL(l);
7497 c = CUR_CHAR(l);
7498 }
7499 buffer[len] = 0;
7500 return(buffer);
7501 }
7502 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007503 if (len == 0)
7504 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007505 return(xmlStrndup(buf, len));
7506}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007507
7508#define MAX_FRAC 20
7509
William M. Brack372a4452004-02-17 13:09:23 +00007510/*
7511 * These are used as divisors for the fractional part of a number.
7512 * Since the table includes 1.0 (representing '0' fractional digits),
7513 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
7514 */
7515static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007516 1.0, 10.0, 100.0, 1000.0, 10000.0,
7517 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7518 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7519 100000000000000.0,
7520 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00007521 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00007522};
7523
Owen Taylor3473f882001-02-23 17:55:21 +00007524/**
7525 * xmlXPathStringEvalNumber:
7526 * @str: A string to scan
7527 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007528 * [30a] Float ::= Number ('e' Digits?)?
7529 *
Owen Taylor3473f882001-02-23 17:55:21 +00007530 * [30] Number ::= Digits ('.' Digits?)?
7531 * | '.' Digits
7532 * [31] Digits ::= [0-9]+
7533 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007534 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007535 * In complement of the Number expression, this function also handles
7536 * negative values : '-' Number.
7537 *
7538 * Returns the double value.
7539 */
7540double
7541xmlXPathStringEvalNumber(const xmlChar *str) {
7542 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007543 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007544 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007545 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007546 int exponent = 0;
7547 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007548#ifdef __GNUC__
7549 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007550 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007551#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007552 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007553 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007554 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7555 return(xmlXPathNAN);
7556 }
7557 if (*cur == '-') {
7558 isneg = 1;
7559 cur++;
7560 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007561
7562#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007563 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007564 * tmp/temp is a workaround against a gcc compiler bug
7565 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007566 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007567 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007568 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007569 ret = ret * 10;
7570 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007571 ok = 1;
7572 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007573 temp = (double) tmp;
7574 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007575 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007576#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007577 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007578 while ((*cur >= '0') && (*cur <= '9')) {
7579 ret = ret * 10 + (*cur - '0');
7580 ok = 1;
7581 cur++;
7582 }
7583#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007584
Owen Taylor3473f882001-02-23 17:55:21 +00007585 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007586 int v, frac = 0;
7587 double fraction = 0;
7588
Owen Taylor3473f882001-02-23 17:55:21 +00007589 cur++;
7590 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7591 return(xmlXPathNAN);
7592 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007593 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7594 v = (*cur - '0');
7595 fraction = fraction * 10 + v;
7596 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007597 cur++;
7598 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007599 fraction /= my_pow10[frac];
7600 ret = ret + fraction;
7601 while ((*cur >= '0') && (*cur <= '9'))
7602 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007603 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007604 if ((*cur == 'e') || (*cur == 'E')) {
7605 cur++;
7606 if (*cur == '-') {
7607 is_exponent_negative = 1;
7608 cur++;
William M. Brack99127052004-05-24 02:52:28 +00007609 } else if (*cur == '+') {
7610 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007611 }
7612 while ((*cur >= '0') && (*cur <= '9')) {
7613 exponent = exponent * 10 + (*cur - '0');
7614 cur++;
7615 }
7616 }
William M. Brack76e95df2003-10-18 16:20:14 +00007617 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007618 if (*cur != 0) return(xmlXPathNAN);
7619 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007620 if (is_exponent_negative) exponent = -exponent;
7621 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007622 return(ret);
7623}
7624
7625/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007626 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007627 * @ctxt: the XPath Parser context
7628 *
7629 * [30] Number ::= Digits ('.' Digits?)?
7630 * | '.' Digits
7631 * [31] Digits ::= [0-9]+
7632 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007633 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007634 *
7635 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007636static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007637xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7638{
Owen Taylor3473f882001-02-23 17:55:21 +00007639 double ret = 0.0;
7640 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007641 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007642 int exponent = 0;
7643 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007644#ifdef __GNUC__
7645 unsigned long tmp = 0;
7646 double temp;
7647#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007648
7649 CHECK_ERROR;
7650 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7651 XP_ERROR(XPATH_NUMBER_ERROR);
7652 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007653#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007654 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007655 * tmp/temp is a workaround against a gcc compiler bug
7656 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007657 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007658 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007659 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007660 ret = ret * 10;
7661 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007662 ok = 1;
7663 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007664 temp = (double) tmp;
7665 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007666 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007667#else
7668 ret = 0;
7669 while ((CUR >= '0') && (CUR <= '9')) {
7670 ret = ret * 10 + (CUR - '0');
7671 ok = 1;
7672 NEXT;
7673 }
7674#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007675 if (CUR == '.') {
7676 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007677 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7678 XP_ERROR(XPATH_NUMBER_ERROR);
7679 }
7680 while ((CUR >= '0') && (CUR <= '9')) {
7681 mult /= 10;
7682 ret = ret + (CUR - '0') * mult;
7683 NEXT;
7684 }
Owen Taylor3473f882001-02-23 17:55:21 +00007685 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007686 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007687 NEXT;
7688 if (CUR == '-') {
7689 is_exponent_negative = 1;
7690 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00007691 } else if (CUR == '+') {
7692 NEXT;
7693 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007694 while ((CUR >= '0') && (CUR <= '9')) {
7695 exponent = exponent * 10 + (CUR - '0');
7696 NEXT;
7697 }
7698 if (is_exponent_negative)
7699 exponent = -exponent;
7700 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007701 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007702 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007703 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007704}
7705
7706/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007707 * xmlXPathParseLiteral:
7708 * @ctxt: the XPath Parser context
7709 *
7710 * Parse a Literal
7711 *
7712 * [29] Literal ::= '"' [^"]* '"'
7713 * | "'" [^']* "'"
7714 *
7715 * Returns the value found or NULL in case of error
7716 */
7717static xmlChar *
7718xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7719 const xmlChar *q;
7720 xmlChar *ret = NULL;
7721
7722 if (CUR == '"') {
7723 NEXT;
7724 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007725 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007726 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007727 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007728 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7729 } else {
7730 ret = xmlStrndup(q, CUR_PTR - q);
7731 NEXT;
7732 }
7733 } else if (CUR == '\'') {
7734 NEXT;
7735 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007736 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007737 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007738 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007739 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7740 } else {
7741 ret = xmlStrndup(q, CUR_PTR - q);
7742 NEXT;
7743 }
7744 } else {
7745 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7746 }
7747 return(ret);
7748}
7749
7750/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007751 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007752 * @ctxt: the XPath Parser context
7753 *
7754 * Parse a Literal and push it on the stack.
7755 *
7756 * [29] Literal ::= '"' [^"]* '"'
7757 * | "'" [^']* "'"
7758 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007759 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007760 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007761static void
7762xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007763 const xmlChar *q;
7764 xmlChar *ret = NULL;
7765
7766 if (CUR == '"') {
7767 NEXT;
7768 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007769 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007770 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007771 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007772 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7773 } else {
7774 ret = xmlStrndup(q, CUR_PTR - q);
7775 NEXT;
7776 }
7777 } else if (CUR == '\'') {
7778 NEXT;
7779 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007780 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007781 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007782 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007783 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7784 } else {
7785 ret = xmlStrndup(q, CUR_PTR - q);
7786 NEXT;
7787 }
7788 } else {
7789 XP_ERROR(XPATH_START_LITERAL_ERROR);
7790 }
7791 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007792 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7793 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007794 xmlFree(ret);
7795}
7796
7797/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007798 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007799 * @ctxt: the XPath Parser context
7800 *
7801 * Parse a VariableReference, evaluate it and push it on the stack.
7802 *
7803 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00007804 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00007805 * of any of the types that are possible for the value of an expression,
7806 * and may also be of additional types not specified here.
7807 *
7808 * Early evaluation is possible since:
7809 * The variable bindings [...] used to evaluate a subexpression are
7810 * always the same as those used to evaluate the containing expression.
7811 *
7812 * [36] VariableReference ::= '$' QName
7813 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007814static void
7815xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007816 xmlChar *name;
7817 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007818
7819 SKIP_BLANKS;
7820 if (CUR != '$') {
7821 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7822 }
7823 NEXT;
7824 name = xmlXPathParseQName(ctxt, &prefix);
7825 if (name == NULL) {
7826 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7827 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007828 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007829 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7830 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007831 SKIP_BLANKS;
7832}
7833
7834/**
7835 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007836 * @name: a name string
7837 *
7838 * Is the name given a NodeType one.
7839 *
7840 * [38] NodeType ::= 'comment'
7841 * | 'text'
7842 * | 'processing-instruction'
7843 * | 'node'
7844 *
7845 * Returns 1 if true 0 otherwise
7846 */
7847int
7848xmlXPathIsNodeType(const xmlChar *name) {
7849 if (name == NULL)
7850 return(0);
7851
Daniel Veillard1971ee22002-01-31 20:29:19 +00007852 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007853 return(1);
7854 if (xmlStrEqual(name, BAD_CAST "text"))
7855 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007856 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007857 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007858 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007859 return(1);
7860 return(0);
7861}
7862
7863/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007864 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007865 * @ctxt: the XPath Parser context
7866 *
7867 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7868 * [17] Argument ::= Expr
7869 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007870 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007871 * pushed on the stack
7872 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007873static void
7874xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007875 xmlChar *name;
7876 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007877 int nbargs = 0;
7878
7879 name = xmlXPathParseQName(ctxt, &prefix);
7880 if (name == NULL) {
7881 XP_ERROR(XPATH_EXPR_ERROR);
7882 }
7883 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007884#ifdef DEBUG_EXPR
7885 if (prefix == NULL)
7886 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7887 name);
7888 else
7889 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7890 prefix, name);
7891#endif
7892
Owen Taylor3473f882001-02-23 17:55:21 +00007893 if (CUR != '(') {
7894 XP_ERROR(XPATH_EXPR_ERROR);
7895 }
7896 NEXT;
7897 SKIP_BLANKS;
7898
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007899 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007900 if (CUR != ')') {
7901 while (CUR != 0) {
7902 int op1 = ctxt->comp->last;
7903 ctxt->comp->last = -1;
7904 xmlXPathCompileExpr(ctxt);
7905 CHECK_ERROR;
7906 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7907 nbargs++;
7908 if (CUR == ')') break;
7909 if (CUR != ',') {
7910 XP_ERROR(XPATH_EXPR_ERROR);
7911 }
7912 NEXT;
7913 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007914 }
Owen Taylor3473f882001-02-23 17:55:21 +00007915 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007916 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7917 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007918 NEXT;
7919 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007920}
7921
7922/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007923 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007924 * @ctxt: the XPath Parser context
7925 *
7926 * [15] PrimaryExpr ::= VariableReference
7927 * | '(' Expr ')'
7928 * | Literal
7929 * | Number
7930 * | FunctionCall
7931 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007932 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007933 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007934static void
7935xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007936 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007937 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007938 else if (CUR == '(') {
7939 NEXT;
7940 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007941 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007942 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007943 if (CUR != ')') {
7944 XP_ERROR(XPATH_EXPR_ERROR);
7945 }
7946 NEXT;
7947 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007948 } else if (IS_DIGIT_CH(CUR) || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007949 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007950 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007951 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007952 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007953 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007954 }
7955 SKIP_BLANKS;
7956}
7957
7958/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007959 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007960 * @ctxt: the XPath Parser context
7961 *
7962 * [20] FilterExpr ::= PrimaryExpr
7963 * | FilterExpr Predicate
7964 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007965 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007966 * Square brackets are used to filter expressions in the same way that
7967 * they are used in location paths. It is an error if the expression to
7968 * be filtered does not evaluate to a node-set. The context node list
7969 * used for evaluating the expression in square brackets is the node-set
7970 * to be filtered listed in document order.
7971 */
7972
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007973static void
7974xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7975 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007976 CHECK_ERROR;
7977 SKIP_BLANKS;
7978
7979 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007980 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007981 SKIP_BLANKS;
7982 }
7983
7984
7985}
7986
7987/**
7988 * xmlXPathScanName:
7989 * @ctxt: the XPath Parser context
7990 *
7991 * Trickery: parse an XML name but without consuming the input flow
7992 * Needed to avoid insanity in the parser state.
7993 *
7994 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7995 * CombiningChar | Extender
7996 *
7997 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7998 *
7999 * [6] Names ::= Name (S Name)*
8000 *
8001 * Returns the Name parsed or NULL
8002 */
8003
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008004static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00008005xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
8006 xmlChar buf[XML_MAX_NAMELEN];
8007 int len = 0;
8008
8009 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00008010 if (!IS_LETTER_CH(CUR) && (CUR != '_') &&
Owen Taylor3473f882001-02-23 17:55:21 +00008011 (CUR != ':')) {
8012 return(NULL);
8013 }
8014
William M. Brack76e95df2003-10-18 16:20:14 +00008015 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008016 (NXT(len) == '.') || (NXT(len) == '-') ||
8017 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00008018 (IS_COMBINING_CH(NXT(len))) ||
8019 (IS_EXTENDER_CH(NXT(len)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008020 buf[len] = NXT(len);
8021 len++;
8022 if (len >= XML_MAX_NAMELEN) {
8023 xmlGenericError(xmlGenericErrorContext,
8024 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
William M. Brack76e95df2003-10-18 16:20:14 +00008025 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008026 (NXT(len) == '.') || (NXT(len) == '-') ||
8027 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00008028 (IS_COMBINING_CH(NXT(len))) ||
8029 (IS_EXTENDER_CH(NXT(len))))
Owen Taylor3473f882001-02-23 17:55:21 +00008030 len++;
8031 break;
8032 }
8033 }
8034 return(xmlStrndup(buf, len));
8035}
8036
8037/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008038 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008039 * @ctxt: the XPath Parser context
8040 *
8041 * [19] PathExpr ::= LocationPath
8042 * | FilterExpr
8043 * | FilterExpr '/' RelativeLocationPath
8044 * | FilterExpr '//' RelativeLocationPath
8045 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008046 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008047 * The / operator and // operators combine an arbitrary expression
8048 * and a relative location path. It is an error if the expression
8049 * does not evaluate to a node-set.
8050 * The / operator does composition in the same way as when / is
8051 * used in a location path. As in location paths, // is short for
8052 * /descendant-or-self::node()/.
8053 */
8054
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008055static void
8056xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008057 int lc = 1; /* Should we branch to LocationPath ? */
8058 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8059
8060 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00008061 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT_CH(CUR)) ||
8062 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008063 lc = 0;
8064 } else if (CUR == '*') {
8065 /* relative or absolute location path */
8066 lc = 1;
8067 } else if (CUR == '/') {
8068 /* relative or absolute location path */
8069 lc = 1;
8070 } else if (CUR == '@') {
8071 /* relative abbreviated attribute location path */
8072 lc = 1;
8073 } else if (CUR == '.') {
8074 /* relative abbreviated attribute location path */
8075 lc = 1;
8076 } else {
8077 /*
8078 * Problem is finding if we have a name here whether it's:
8079 * - a nodetype
8080 * - a function call in which case it's followed by '('
8081 * - an axis in which case it's followed by ':'
8082 * - a element name
8083 * We do an a priori analysis here rather than having to
8084 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008085 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008086 * read/write/debug.
8087 */
8088 SKIP_BLANKS;
8089 name = xmlXPathScanName(ctxt);
8090 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8091#ifdef DEBUG_STEP
8092 xmlGenericError(xmlGenericErrorContext,
8093 "PathExpr: Axis\n");
8094#endif
8095 lc = 1;
8096 xmlFree(name);
8097 } else if (name != NULL) {
8098 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008099
8100
8101 while (NXT(len) != 0) {
8102 if (NXT(len) == '/') {
8103 /* element name */
8104#ifdef DEBUG_STEP
8105 xmlGenericError(xmlGenericErrorContext,
8106 "PathExpr: AbbrRelLocation\n");
8107#endif
8108 lc = 1;
8109 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008110 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008111 /* ignore blanks */
8112 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008113 } else if (NXT(len) == ':') {
8114#ifdef DEBUG_STEP
8115 xmlGenericError(xmlGenericErrorContext,
8116 "PathExpr: AbbrRelLocation\n");
8117#endif
8118 lc = 1;
8119 break;
8120 } else if ((NXT(len) == '(')) {
8121 /* Note Type or Function */
8122 if (xmlXPathIsNodeType(name)) {
8123#ifdef DEBUG_STEP
8124 xmlGenericError(xmlGenericErrorContext,
8125 "PathExpr: Type search\n");
8126#endif
8127 lc = 1;
8128 } else {
8129#ifdef DEBUG_STEP
8130 xmlGenericError(xmlGenericErrorContext,
8131 "PathExpr: function call\n");
8132#endif
8133 lc = 0;
8134 }
8135 break;
8136 } else if ((NXT(len) == '[')) {
8137 /* element name */
8138#ifdef DEBUG_STEP
8139 xmlGenericError(xmlGenericErrorContext,
8140 "PathExpr: AbbrRelLocation\n");
8141#endif
8142 lc = 1;
8143 break;
8144 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8145 (NXT(len) == '=')) {
8146 lc = 1;
8147 break;
8148 } else {
8149 lc = 1;
8150 break;
8151 }
8152 len++;
8153 }
8154 if (NXT(len) == 0) {
8155#ifdef DEBUG_STEP
8156 xmlGenericError(xmlGenericErrorContext,
8157 "PathExpr: AbbrRelLocation\n");
8158#endif
8159 /* element name */
8160 lc = 1;
8161 }
8162 xmlFree(name);
8163 } else {
William M. Brack08171912003-12-29 02:52:11 +00008164 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008165 XP_ERROR(XPATH_EXPR_ERROR);
8166 }
8167 }
8168
8169 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008170 if (CUR == '/') {
8171 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8172 } else {
8173 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008174 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008175 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008176 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008177 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008178 CHECK_ERROR;
8179 if ((CUR == '/') && (NXT(1) == '/')) {
8180 SKIP(2);
8181 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008182
8183 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8184 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8185 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8186
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008187 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008188 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008189 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008190 }
8191 }
8192 SKIP_BLANKS;
8193}
8194
8195/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008196 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008197 * @ctxt: the XPath Parser context
8198 *
8199 * [18] UnionExpr ::= PathExpr
8200 * | UnionExpr '|' PathExpr
8201 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008202 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008203 */
8204
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008205static void
8206xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8207 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008208 CHECK_ERROR;
8209 SKIP_BLANKS;
8210 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008211 int op1 = ctxt->comp->last;
8212 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008213
8214 NEXT;
8215 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008216 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008217
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008218 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8219
Owen Taylor3473f882001-02-23 17:55:21 +00008220 SKIP_BLANKS;
8221 }
Owen Taylor3473f882001-02-23 17:55:21 +00008222}
8223
8224/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008225 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008226 * @ctxt: the XPath Parser context
8227 *
8228 * [27] UnaryExpr ::= UnionExpr
8229 * | '-' UnaryExpr
8230 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008231 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008232 */
8233
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008234static void
8235xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008236 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008237 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008238
8239 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008240 while (CUR == '-') {
8241 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008242 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008243 NEXT;
8244 SKIP_BLANKS;
8245 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008246
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008247 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008248 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008249 if (found) {
8250 if (minus)
8251 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8252 else
8253 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008254 }
8255}
8256
8257/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008258 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008259 * @ctxt: the XPath Parser context
8260 *
8261 * [26] MultiplicativeExpr ::= UnaryExpr
8262 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8263 * | MultiplicativeExpr 'div' UnaryExpr
8264 * | MultiplicativeExpr 'mod' UnaryExpr
8265 * [34] MultiplyOperator ::= '*'
8266 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008267 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008268 */
8269
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008270static void
8271xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8272 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008273 CHECK_ERROR;
8274 SKIP_BLANKS;
8275 while ((CUR == '*') ||
8276 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8277 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8278 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008279 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008280
8281 if (CUR == '*') {
8282 op = 0;
8283 NEXT;
8284 } else if (CUR == 'd') {
8285 op = 1;
8286 SKIP(3);
8287 } else if (CUR == 'm') {
8288 op = 2;
8289 SKIP(3);
8290 }
8291 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008292 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008293 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008294 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008295 SKIP_BLANKS;
8296 }
8297}
8298
8299/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008300 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008301 * @ctxt: the XPath Parser context
8302 *
8303 * [25] AdditiveExpr ::= MultiplicativeExpr
8304 * | AdditiveExpr '+' MultiplicativeExpr
8305 * | AdditiveExpr '-' MultiplicativeExpr
8306 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008307 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008308 */
8309
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008310static void
8311xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008312
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008313 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008314 CHECK_ERROR;
8315 SKIP_BLANKS;
8316 while ((CUR == '+') || (CUR == '-')) {
8317 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008318 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008319
8320 if (CUR == '+') plus = 1;
8321 else plus = 0;
8322 NEXT;
8323 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008324 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008325 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008326 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008327 SKIP_BLANKS;
8328 }
8329}
8330
8331/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008332 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008333 * @ctxt: the XPath Parser context
8334 *
8335 * [24] RelationalExpr ::= AdditiveExpr
8336 * | RelationalExpr '<' AdditiveExpr
8337 * | RelationalExpr '>' AdditiveExpr
8338 * | RelationalExpr '<=' AdditiveExpr
8339 * | RelationalExpr '>=' AdditiveExpr
8340 *
8341 * A <= B > C is allowed ? Answer from James, yes with
8342 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8343 * which is basically what got implemented.
8344 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008345 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008346 * on the stack
8347 */
8348
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008349static void
8350xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8351 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008352 CHECK_ERROR;
8353 SKIP_BLANKS;
8354 while ((CUR == '<') ||
8355 (CUR == '>') ||
8356 ((CUR == '<') && (NXT(1) == '=')) ||
8357 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008358 int inf, strict;
8359 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008360
8361 if (CUR == '<') inf = 1;
8362 else inf = 0;
8363 if (NXT(1) == '=') strict = 0;
8364 else strict = 1;
8365 NEXT;
8366 if (!strict) NEXT;
8367 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008368 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008369 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008370 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008371 SKIP_BLANKS;
8372 }
8373}
8374
8375/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008376 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008377 * @ctxt: the XPath Parser context
8378 *
8379 * [23] EqualityExpr ::= RelationalExpr
8380 * | EqualityExpr '=' RelationalExpr
8381 * | EqualityExpr '!=' RelationalExpr
8382 *
8383 * A != B != C is allowed ? Answer from James, yes with
8384 * (RelationalExpr = RelationalExpr) = RelationalExpr
8385 * (RelationalExpr != RelationalExpr) != RelationalExpr
8386 * which is basically what got implemented.
8387 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008388 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008389 *
8390 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008391static void
8392xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8393 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008394 CHECK_ERROR;
8395 SKIP_BLANKS;
8396 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008397 int eq;
8398 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008399
8400 if (CUR == '=') eq = 1;
8401 else eq = 0;
8402 NEXT;
8403 if (!eq) NEXT;
8404 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008405 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008406 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008407 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008408 SKIP_BLANKS;
8409 }
8410}
8411
8412/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008413 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008414 * @ctxt: the XPath Parser context
8415 *
8416 * [22] AndExpr ::= EqualityExpr
8417 * | AndExpr 'and' EqualityExpr
8418 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008419 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008420 *
8421 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008422static void
8423xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8424 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008425 CHECK_ERROR;
8426 SKIP_BLANKS;
8427 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008428 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008429 SKIP(3);
8430 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008431 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008432 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008433 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008434 SKIP_BLANKS;
8435 }
8436}
8437
8438/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008439 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008440 * @ctxt: the XPath Parser context
8441 *
8442 * [14] Expr ::= OrExpr
8443 * [21] OrExpr ::= AndExpr
8444 * | OrExpr 'or' AndExpr
8445 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008446 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008447 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008448static void
8449xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8450 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008451 CHECK_ERROR;
8452 SKIP_BLANKS;
8453 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008454 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008455 SKIP(2);
8456 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008457 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008458 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008459 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8460 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008461 SKIP_BLANKS;
8462 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008463 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8464 /* more ops could be optimized too */
8465 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8466 }
Owen Taylor3473f882001-02-23 17:55:21 +00008467}
8468
8469/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008470 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008471 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008472 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008473 *
8474 * [8] Predicate ::= '[' PredicateExpr ']'
8475 * [9] PredicateExpr ::= Expr
8476 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008477 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008478 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008479static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008480xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008481 int op1 = ctxt->comp->last;
8482
8483 SKIP_BLANKS;
8484 if (CUR != '[') {
8485 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8486 }
8487 NEXT;
8488 SKIP_BLANKS;
8489
8490 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008491 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008492 CHECK_ERROR;
8493
8494 if (CUR != ']') {
8495 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8496 }
8497
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008498 if (filter)
8499 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8500 else
8501 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008502
8503 NEXT;
8504 SKIP_BLANKS;
8505}
8506
8507/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008508 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008509 * @ctxt: the XPath Parser context
8510 * @test: pointer to a xmlXPathTestVal
8511 * @type: pointer to a xmlXPathTypeVal
8512 * @prefix: placeholder for a possible name prefix
8513 *
8514 * [7] NodeTest ::= NameTest
8515 * | NodeType '(' ')'
8516 * | 'processing-instruction' '(' Literal ')'
8517 *
8518 * [37] NameTest ::= '*'
8519 * | NCName ':' '*'
8520 * | QName
8521 * [38] NodeType ::= 'comment'
8522 * | 'text'
8523 * | 'processing-instruction'
8524 * | 'node'
8525 *
William M. Brack08171912003-12-29 02:52:11 +00008526 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00008527 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008528static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008529xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8530 xmlXPathTypeVal *type, const xmlChar **prefix,
8531 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008532 int blanks;
8533
8534 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8535 STRANGE;
8536 return(NULL);
8537 }
William M. Brack78637da2003-07-31 14:47:38 +00008538 *type = (xmlXPathTypeVal) 0;
8539 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008540 *prefix = NULL;
8541 SKIP_BLANKS;
8542
8543 if ((name == NULL) && (CUR == '*')) {
8544 /*
8545 * All elements
8546 */
8547 NEXT;
8548 *test = NODE_TEST_ALL;
8549 return(NULL);
8550 }
8551
8552 if (name == NULL)
8553 name = xmlXPathParseNCName(ctxt);
8554 if (name == NULL) {
8555 XP_ERROR0(XPATH_EXPR_ERROR);
8556 }
8557
William M. Brack76e95df2003-10-18 16:20:14 +00008558 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008559 SKIP_BLANKS;
8560 if (CUR == '(') {
8561 NEXT;
8562 /*
8563 * NodeType or PI search
8564 */
8565 if (xmlStrEqual(name, BAD_CAST "comment"))
8566 *type = NODE_TYPE_COMMENT;
8567 else if (xmlStrEqual(name, BAD_CAST "node"))
8568 *type = NODE_TYPE_NODE;
8569 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8570 *type = NODE_TYPE_PI;
8571 else if (xmlStrEqual(name, BAD_CAST "text"))
8572 *type = NODE_TYPE_TEXT;
8573 else {
8574 if (name != NULL)
8575 xmlFree(name);
8576 XP_ERROR0(XPATH_EXPR_ERROR);
8577 }
8578
8579 *test = NODE_TEST_TYPE;
8580
8581 SKIP_BLANKS;
8582 if (*type == NODE_TYPE_PI) {
8583 /*
8584 * Specific case: search a PI by name.
8585 */
Owen Taylor3473f882001-02-23 17:55:21 +00008586 if (name != NULL)
8587 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008588 name = NULL;
8589 if (CUR != ')') {
8590 name = xmlXPathParseLiteral(ctxt);
8591 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008592 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008593 SKIP_BLANKS;
8594 }
Owen Taylor3473f882001-02-23 17:55:21 +00008595 }
8596 if (CUR != ')') {
8597 if (name != NULL)
8598 xmlFree(name);
8599 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8600 }
8601 NEXT;
8602 return(name);
8603 }
8604 *test = NODE_TEST_NAME;
8605 if ((!blanks) && (CUR == ':')) {
8606 NEXT;
8607
8608 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008609 * Since currently the parser context don't have a
8610 * namespace list associated:
8611 * The namespace name for this prefix can be computed
8612 * only at evaluation time. The compilation is done
8613 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008614 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008615#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008616 *prefix = xmlXPathNsLookup(ctxt->context, name);
8617 if (name != NULL)
8618 xmlFree(name);
8619 if (*prefix == NULL) {
8620 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8621 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008622#else
8623 *prefix = name;
8624#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008625
8626 if (CUR == '*') {
8627 /*
8628 * All elements
8629 */
8630 NEXT;
8631 *test = NODE_TEST_ALL;
8632 return(NULL);
8633 }
8634
8635 name = xmlXPathParseNCName(ctxt);
8636 if (name == NULL) {
8637 XP_ERROR0(XPATH_EXPR_ERROR);
8638 }
8639 }
8640 return(name);
8641}
8642
8643/**
8644 * xmlXPathIsAxisName:
8645 * @name: a preparsed name token
8646 *
8647 * [6] AxisName ::= 'ancestor'
8648 * | 'ancestor-or-self'
8649 * | 'attribute'
8650 * | 'child'
8651 * | 'descendant'
8652 * | 'descendant-or-self'
8653 * | 'following'
8654 * | 'following-sibling'
8655 * | 'namespace'
8656 * | 'parent'
8657 * | 'preceding'
8658 * | 'preceding-sibling'
8659 * | 'self'
8660 *
8661 * Returns the axis or 0
8662 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008663static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008664xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008665 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008666 switch (name[0]) {
8667 case 'a':
8668 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8669 ret = AXIS_ANCESTOR;
8670 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8671 ret = AXIS_ANCESTOR_OR_SELF;
8672 if (xmlStrEqual(name, BAD_CAST "attribute"))
8673 ret = AXIS_ATTRIBUTE;
8674 break;
8675 case 'c':
8676 if (xmlStrEqual(name, BAD_CAST "child"))
8677 ret = AXIS_CHILD;
8678 break;
8679 case 'd':
8680 if (xmlStrEqual(name, BAD_CAST "descendant"))
8681 ret = AXIS_DESCENDANT;
8682 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8683 ret = AXIS_DESCENDANT_OR_SELF;
8684 break;
8685 case 'f':
8686 if (xmlStrEqual(name, BAD_CAST "following"))
8687 ret = AXIS_FOLLOWING;
8688 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8689 ret = AXIS_FOLLOWING_SIBLING;
8690 break;
8691 case 'n':
8692 if (xmlStrEqual(name, BAD_CAST "namespace"))
8693 ret = AXIS_NAMESPACE;
8694 break;
8695 case 'p':
8696 if (xmlStrEqual(name, BAD_CAST "parent"))
8697 ret = AXIS_PARENT;
8698 if (xmlStrEqual(name, BAD_CAST "preceding"))
8699 ret = AXIS_PRECEDING;
8700 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8701 ret = AXIS_PRECEDING_SIBLING;
8702 break;
8703 case 's':
8704 if (xmlStrEqual(name, BAD_CAST "self"))
8705 ret = AXIS_SELF;
8706 break;
8707 }
8708 return(ret);
8709}
8710
8711/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008712 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008713 * @ctxt: the XPath Parser context
8714 *
8715 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8716 * | AbbreviatedStep
8717 *
8718 * [12] AbbreviatedStep ::= '.' | '..'
8719 *
8720 * [5] AxisSpecifier ::= AxisName '::'
8721 * | AbbreviatedAxisSpecifier
8722 *
8723 * [13] AbbreviatedAxisSpecifier ::= '@'?
8724 *
8725 * Modified for XPtr range support as:
8726 *
8727 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8728 * | AbbreviatedStep
8729 * | 'range-to' '(' Expr ')' Predicate*
8730 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008731 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008732 * A location step of . is short for self::node(). This is
8733 * particularly useful in conjunction with //. For example, the
8734 * location path .//para is short for
8735 * self::node()/descendant-or-self::node()/child::para
8736 * and so will select all para descendant elements of the context
8737 * node.
8738 * Similarly, a location step of .. is short for parent::node().
8739 * For example, ../title is short for parent::node()/child::title
8740 * and so will select the title children of the parent of the context
8741 * node.
8742 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008743static void
8744xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008745#ifdef LIBXML_XPTR_ENABLED
8746 int rangeto = 0;
8747 int op2 = -1;
8748#endif
8749
Owen Taylor3473f882001-02-23 17:55:21 +00008750 SKIP_BLANKS;
8751 if ((CUR == '.') && (NXT(1) == '.')) {
8752 SKIP(2);
8753 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008754 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8755 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008756 } else if (CUR == '.') {
8757 NEXT;
8758 SKIP_BLANKS;
8759 } else {
8760 xmlChar *name = NULL;
8761 const xmlChar *prefix = NULL;
8762 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008763 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008764 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008765 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008766
8767 /*
8768 * The modification needed for XPointer change to the production
8769 */
8770#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008771 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008772 name = xmlXPathParseNCName(ctxt);
8773 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008774 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008775 xmlFree(name);
8776 SKIP_BLANKS;
8777 if (CUR != '(') {
8778 XP_ERROR(XPATH_EXPR_ERROR);
8779 }
8780 NEXT;
8781 SKIP_BLANKS;
8782
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008783 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008784 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008785 CHECK_ERROR;
8786
8787 SKIP_BLANKS;
8788 if (CUR != ')') {
8789 XP_ERROR(XPATH_EXPR_ERROR);
8790 }
8791 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008792 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008793 goto eval_predicates;
8794 }
8795 }
8796#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008797 if (CUR == '*') {
8798 axis = AXIS_CHILD;
8799 } else {
8800 if (name == NULL)
8801 name = xmlXPathParseNCName(ctxt);
8802 if (name != NULL) {
8803 axis = xmlXPathIsAxisName(name);
8804 if (axis != 0) {
8805 SKIP_BLANKS;
8806 if ((CUR == ':') && (NXT(1) == ':')) {
8807 SKIP(2);
8808 xmlFree(name);
8809 name = NULL;
8810 } else {
8811 /* an element name can conflict with an axis one :-\ */
8812 axis = AXIS_CHILD;
8813 }
Owen Taylor3473f882001-02-23 17:55:21 +00008814 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008815 axis = AXIS_CHILD;
8816 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008817 } else if (CUR == '@') {
8818 NEXT;
8819 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008820 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008821 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008822 }
Owen Taylor3473f882001-02-23 17:55:21 +00008823 }
8824
8825 CHECK_ERROR;
8826
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008827 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008828 if (test == 0)
8829 return;
8830
8831#ifdef DEBUG_STEP
8832 xmlGenericError(xmlGenericErrorContext,
8833 "Basis : computing new set\n");
8834#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008835
Owen Taylor3473f882001-02-23 17:55:21 +00008836#ifdef DEBUG_STEP
8837 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008838 if (ctxt->value == NULL)
8839 xmlGenericError(xmlGenericErrorContext, "no value\n");
8840 else if (ctxt->value->nodesetval == NULL)
8841 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8842 else
8843 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008844#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008845
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008846#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008847eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008848#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008849 op1 = ctxt->comp->last;
8850 ctxt->comp->last = -1;
8851
Owen Taylor3473f882001-02-23 17:55:21 +00008852 SKIP_BLANKS;
8853 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008854 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008855 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008856
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008857#ifdef LIBXML_XPTR_ENABLED
8858 if (rangeto) {
8859 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8860 } else
8861#endif
8862 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8863 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008864
Owen Taylor3473f882001-02-23 17:55:21 +00008865 }
8866#ifdef DEBUG_STEP
8867 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008868 if (ctxt->value == NULL)
8869 xmlGenericError(xmlGenericErrorContext, "no value\n");
8870 else if (ctxt->value->nodesetval == NULL)
8871 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8872 else
8873 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8874 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008875#endif
8876}
8877
8878/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008879 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008880 * @ctxt: the XPath Parser context
8881 *
8882 * [3] RelativeLocationPath ::= Step
8883 * | RelativeLocationPath '/' Step
8884 * | AbbreviatedRelativeLocationPath
8885 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8886 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008887 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008888 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008889static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008890xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008891(xmlXPathParserContextPtr ctxt) {
8892 SKIP_BLANKS;
8893 if ((CUR == '/') && (NXT(1) == '/')) {
8894 SKIP(2);
8895 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008896 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8897 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008898 } else if (CUR == '/') {
8899 NEXT;
8900 SKIP_BLANKS;
8901 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008902 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008903 SKIP_BLANKS;
8904 while (CUR == '/') {
8905 if ((CUR == '/') && (NXT(1) == '/')) {
8906 SKIP(2);
8907 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008908 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008909 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008910 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008911 } else if (CUR == '/') {
8912 NEXT;
8913 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008914 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008915 }
8916 SKIP_BLANKS;
8917 }
8918}
8919
8920/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008921 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008922 * @ctxt: the XPath Parser context
8923 *
8924 * [1] LocationPath ::= RelativeLocationPath
8925 * | AbsoluteLocationPath
8926 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8927 * | AbbreviatedAbsoluteLocationPath
8928 * [10] AbbreviatedAbsoluteLocationPath ::=
8929 * '//' RelativeLocationPath
8930 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008931 * Compile a location path
8932 *
Owen Taylor3473f882001-02-23 17:55:21 +00008933 * // is short for /descendant-or-self::node()/. For example,
8934 * //para is short for /descendant-or-self::node()/child::para and
8935 * so will select any para element in the document (even a para element
8936 * that is a document element will be selected by //para since the
8937 * document element node is a child of the root node); div//para is
8938 * short for div/descendant-or-self::node()/child::para and so will
8939 * select all para descendants of div children.
8940 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008941static void
8942xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008943 SKIP_BLANKS;
8944 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008945 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008946 } else {
8947 while (CUR == '/') {
8948 if ((CUR == '/') && (NXT(1) == '/')) {
8949 SKIP(2);
8950 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008951 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8952 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008953 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008954 } else if (CUR == '/') {
8955 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008956 SKIP_BLANKS;
8957 if ((CUR != 0 ) &&
William M. Brack76e95df2003-10-18 16:20:14 +00008958 ((IS_LETTER_CH(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00008959 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008960 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008961 }
8962 }
8963 }
8964}
8965
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008966/************************************************************************
8967 * *
8968 * XPath precompiled expression evaluation *
8969 * *
8970 ************************************************************************/
8971
Daniel Veillardf06307e2001-07-03 10:35:50 +00008972static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008973xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8974
8975/**
8976 * xmlXPathNodeCollectAndTest:
8977 * @ctxt: the XPath Parser context
8978 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008979 * @first: pointer to the first element in document order
8980 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008981 *
8982 * This is the function implementing a step: based on the current list
8983 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00008984 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008985 *
8986 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008987 *
William M. Brack08171912003-12-29 02:52:11 +00008988 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008989 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008990static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008991xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008992 xmlXPathStepOpPtr op,
8993 xmlNodePtr * first, xmlNodePtr * last)
8994{
William M. Brack78637da2003-07-31 14:47:38 +00008995 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
8996 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
8997 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008998 const xmlChar *prefix = op->value4;
8999 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009000 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009001
9002#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009003 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009004#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009005 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009006 xmlNodeSetPtr ret, list;
9007 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009008 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00009009 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009010 xmlNodePtr cur = NULL;
9011 xmlXPathObjectPtr obj;
9012 xmlNodeSetPtr nodelist;
9013 xmlNodePtr tmp;
9014
Daniel Veillardf06307e2001-07-03 10:35:50 +00009015 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009016 obj = valuePop(ctxt);
9017 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009018 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009019 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009020 URI = xmlXPathNsLookup(ctxt->context, prefix);
9021 if (URI == NULL)
9022 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00009023 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009024#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009025 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009026#endif
9027 switch (axis) {
9028 case AXIS_ANCESTOR:
9029#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009030 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009031#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009032 first = NULL;
9033 next = xmlXPathNextAncestor;
9034 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009035 case AXIS_ANCESTOR_OR_SELF:
9036#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009037 xmlGenericError(xmlGenericErrorContext,
9038 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009039#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009040 first = NULL;
9041 next = xmlXPathNextAncestorOrSelf;
9042 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009043 case AXIS_ATTRIBUTE:
9044#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009045 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009046#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009047 first = NULL;
9048 last = NULL;
9049 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009050 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009051 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009052 case AXIS_CHILD:
9053#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009054 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009055#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009056 last = NULL;
9057 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009058 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009059 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009060 case AXIS_DESCENDANT:
9061#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009062 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009063#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009064 last = NULL;
9065 next = xmlXPathNextDescendant;
9066 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009067 case AXIS_DESCENDANT_OR_SELF:
9068#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009069 xmlGenericError(xmlGenericErrorContext,
9070 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009071#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009072 last = NULL;
9073 next = xmlXPathNextDescendantOrSelf;
9074 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009075 case AXIS_FOLLOWING:
9076#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009077 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009078#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009079 last = NULL;
9080 next = xmlXPathNextFollowing;
9081 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009082 case AXIS_FOLLOWING_SIBLING:
9083#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009084 xmlGenericError(xmlGenericErrorContext,
9085 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009086#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009087 last = NULL;
9088 next = xmlXPathNextFollowingSibling;
9089 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009090 case AXIS_NAMESPACE:
9091#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009092 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009093#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009094 first = NULL;
9095 last = NULL;
9096 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009097 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009098 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009099 case AXIS_PARENT:
9100#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009101 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009102#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009103 first = NULL;
9104 next = xmlXPathNextParent;
9105 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009106 case AXIS_PRECEDING:
9107#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009108 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009109#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009110 first = NULL;
9111 next = xmlXPathNextPrecedingInternal;
9112 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009113 case AXIS_PRECEDING_SIBLING:
9114#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009115 xmlGenericError(xmlGenericErrorContext,
9116 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009117#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009118 first = NULL;
9119 next = xmlXPathNextPrecedingSibling;
9120 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009121 case AXIS_SELF:
9122#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009123 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009124#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009125 first = NULL;
9126 last = NULL;
9127 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009128 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009129 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009130 }
9131 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009132 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009133
9134 nodelist = obj->nodesetval;
9135 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009136 xmlXPathFreeObject(obj);
9137 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9138 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009139 }
9140 addNode = xmlXPathNodeSetAddUnique;
9141 ret = NULL;
9142#ifdef DEBUG_STEP
9143 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009144 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009145 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009146 case NODE_TEST_NONE:
9147 xmlGenericError(xmlGenericErrorContext,
9148 " searching for none !!!\n");
9149 break;
9150 case NODE_TEST_TYPE:
9151 xmlGenericError(xmlGenericErrorContext,
9152 " searching for type %d\n", type);
9153 break;
9154 case NODE_TEST_PI:
9155 xmlGenericError(xmlGenericErrorContext,
9156 " searching for PI !!!\n");
9157 break;
9158 case NODE_TEST_ALL:
9159 xmlGenericError(xmlGenericErrorContext,
9160 " searching for *\n");
9161 break;
9162 case NODE_TEST_NS:
9163 xmlGenericError(xmlGenericErrorContext,
9164 " searching for namespace %s\n",
9165 prefix);
9166 break;
9167 case NODE_TEST_NAME:
9168 xmlGenericError(xmlGenericErrorContext,
9169 " searching for name %s\n", name);
9170 if (prefix != NULL)
9171 xmlGenericError(xmlGenericErrorContext,
9172 " with namespace %s\n", prefix);
9173 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009174 }
9175 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9176#endif
9177 /*
9178 * 2.3 Node Tests
9179 * - For the attribute axis, the principal node type is attribute.
9180 * - For the namespace axis, the principal node type is namespace.
9181 * - For other axes, the principal node type is element.
9182 *
9183 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009184 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009185 * select all element children of the context node
9186 */
9187 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009188 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009189 ctxt->context->node = nodelist->nodeTab[i];
9190
Daniel Veillardf06307e2001-07-03 10:35:50 +00009191 cur = NULL;
9192 list = xmlXPathNodeSetCreate(NULL);
9193 do {
9194 cur = next(ctxt, cur);
9195 if (cur == NULL)
9196 break;
9197 if ((first != NULL) && (*first == cur))
9198 break;
9199 if (((t % 256) == 0) &&
9200 (first != NULL) && (*first != NULL) &&
9201 (xmlXPathCmpNodes(*first, cur) >= 0))
9202 break;
9203 if ((last != NULL) && (*last == cur))
9204 break;
9205 if (((t % 256) == 0) &&
9206 (last != NULL) && (*last != NULL) &&
9207 (xmlXPathCmpNodes(cur, *last) >= 0))
9208 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009209 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009210#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009211 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9212#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009213 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009214 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009215 ctxt->context->node = tmp;
9216 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009217 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009218 if ((cur->type == type) ||
9219 ((type == NODE_TYPE_NODE) &&
9220 ((cur->type == XML_DOCUMENT_NODE) ||
9221 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9222 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009223 (cur->type == XML_NAMESPACE_DECL) ||
9224 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009225 (cur->type == XML_PI_NODE) ||
9226 (cur->type == XML_COMMENT_NODE) ||
9227 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009228 (cur->type == XML_TEXT_NODE))) ||
9229 ((type == NODE_TYPE_TEXT) &&
9230 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009231#ifdef DEBUG_STEP
9232 n++;
9233#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009234 addNode(list, cur);
9235 }
9236 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009237 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009238 if (cur->type == XML_PI_NODE) {
9239 if ((name != NULL) &&
9240 (!xmlStrEqual(name, cur->name)))
9241 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009242#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009243 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009244#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009245 addNode(list, cur);
9246 }
9247 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009248 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009249 if (axis == AXIS_ATTRIBUTE) {
9250 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009251#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009252 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009253#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009254 addNode(list, cur);
9255 }
9256 } else if (axis == AXIS_NAMESPACE) {
9257 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009258#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009259 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009260#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009261 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9262 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009263 }
9264 } else {
9265 if (cur->type == XML_ELEMENT_NODE) {
9266 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009267#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009268 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009269#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009270 addNode(list, cur);
9271 } else if ((cur->ns != NULL) &&
9272 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009273#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009274 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009275#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009276 addNode(list, cur);
9277 }
9278 }
9279 }
9280 break;
9281 case NODE_TEST_NS:{
9282 TODO;
9283 break;
9284 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009285 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009286 switch (cur->type) {
9287 case XML_ELEMENT_NODE:
9288 if (xmlStrEqual(name, cur->name)) {
9289 if (prefix == NULL) {
9290 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009291#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009292 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009293#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009294 addNode(list, cur);
9295 }
9296 } else {
9297 if ((cur->ns != NULL) &&
9298 (xmlStrEqual(URI,
9299 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009300#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009301 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009302#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009303 addNode(list, cur);
9304 }
9305 }
9306 }
9307 break;
9308 case XML_ATTRIBUTE_NODE:{
9309 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009310
Daniel Veillardf06307e2001-07-03 10:35:50 +00009311 if (xmlStrEqual(name, attr->name)) {
9312 if (prefix == NULL) {
9313 if ((attr->ns == NULL) ||
9314 (attr->ns->prefix == NULL)) {
9315#ifdef DEBUG_STEP
9316 n++;
9317#endif
9318 addNode(list,
9319 (xmlNodePtr) attr);
9320 }
9321 } else {
9322 if ((attr->ns != NULL) &&
9323 (xmlStrEqual(URI,
9324 attr->ns->
9325 href))) {
9326#ifdef DEBUG_STEP
9327 n++;
9328#endif
9329 addNode(list,
9330 (xmlNodePtr) attr);
9331 }
9332 }
9333 }
9334 break;
9335 }
9336 case XML_NAMESPACE_DECL:
9337 if (cur->type == XML_NAMESPACE_DECL) {
9338 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009339
Daniel Veillardf06307e2001-07-03 10:35:50 +00009340 if ((ns->prefix != NULL) && (name != NULL)
9341 && (xmlStrEqual(ns->prefix, name))) {
9342#ifdef DEBUG_STEP
9343 n++;
9344#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009345 xmlXPathNodeSetAddNs(list,
9346 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009347 }
9348 }
9349 break;
9350 default:
9351 break;
9352 }
9353 break;
9354 break;
9355 }
9356 } while (cur != NULL);
9357
9358 /*
9359 * If there is some predicate filtering do it now
9360 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009361 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009362 xmlXPathObjectPtr obj2;
9363
9364 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9365 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9366 CHECK_TYPE0(XPATH_NODESET);
9367 obj2 = valuePop(ctxt);
9368 list = obj2->nodesetval;
9369 obj2->nodesetval = NULL;
9370 xmlXPathFreeObject(obj2);
9371 }
9372 if (ret == NULL) {
9373 ret = list;
9374 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009375 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009376 xmlXPathFreeNodeSet(list);
9377 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009378 }
9379 ctxt->context->node = tmp;
9380#ifdef DEBUG_STEP
9381 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009382 "\nExamined %d nodes, found %d nodes at that step\n",
9383 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009384#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009385 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009386 if ((obj->boolval) && (obj->user != NULL)) {
9387 ctxt->value->boolval = 1;
9388 ctxt->value->user = obj->user;
9389 obj->user = NULL;
9390 obj->boolval = 0;
9391 }
9392 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009393 return(t);
9394}
9395
9396/**
9397 * xmlXPathNodeCollectAndTestNth:
9398 * @ctxt: the XPath Parser context
9399 * @op: the XPath precompiled step operation
9400 * @indx: the index to collect
9401 * @first: pointer to the first element in document order
9402 * @last: pointer to the last element in document order
9403 *
9404 * This is the function implementing a step: based on the current list
9405 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009406 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009407 *
9408 * Pushes the new NodeSet resulting from the search.
9409 * Returns the number of node traversed
9410 */
9411static int
9412xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9413 xmlXPathStepOpPtr op, int indx,
9414 xmlNodePtr * first, xmlNodePtr * last)
9415{
William M. Brack78637da2003-07-31 14:47:38 +00009416 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9417 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9418 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009419 const xmlChar *prefix = op->value4;
9420 const xmlChar *name = op->value5;
9421 const xmlChar *URI = NULL;
9422 int n = 0, t = 0;
9423
9424 int i;
9425 xmlNodeSetPtr list;
9426 xmlXPathTraversalFunction next = NULL;
9427 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9428 xmlNodePtr cur = NULL;
9429 xmlXPathObjectPtr obj;
9430 xmlNodeSetPtr nodelist;
9431 xmlNodePtr tmp;
9432
9433 CHECK_TYPE0(XPATH_NODESET);
9434 obj = valuePop(ctxt);
9435 addNode = xmlXPathNodeSetAdd;
9436 if (prefix != NULL) {
9437 URI = xmlXPathNsLookup(ctxt->context, prefix);
9438 if (URI == NULL)
9439 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9440 }
9441#ifdef DEBUG_STEP_NTH
9442 xmlGenericError(xmlGenericErrorContext, "new step : ");
9443 if (first != NULL) {
9444 if (*first != NULL)
9445 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9446 (*first)->name);
9447 else
9448 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9449 }
9450 if (last != NULL) {
9451 if (*last != NULL)
9452 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9453 (*last)->name);
9454 else
9455 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9456 }
9457#endif
9458 switch (axis) {
9459 case AXIS_ANCESTOR:
9460#ifdef DEBUG_STEP_NTH
9461 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9462#endif
9463 first = NULL;
9464 next = xmlXPathNextAncestor;
9465 break;
9466 case AXIS_ANCESTOR_OR_SELF:
9467#ifdef DEBUG_STEP_NTH
9468 xmlGenericError(xmlGenericErrorContext,
9469 "axis 'ancestors-or-self' ");
9470#endif
9471 first = NULL;
9472 next = xmlXPathNextAncestorOrSelf;
9473 break;
9474 case AXIS_ATTRIBUTE:
9475#ifdef DEBUG_STEP_NTH
9476 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9477#endif
9478 first = NULL;
9479 last = NULL;
9480 next = xmlXPathNextAttribute;
9481 break;
9482 case AXIS_CHILD:
9483#ifdef DEBUG_STEP_NTH
9484 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9485#endif
9486 last = NULL;
9487 next = xmlXPathNextChild;
9488 break;
9489 case AXIS_DESCENDANT:
9490#ifdef DEBUG_STEP_NTH
9491 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9492#endif
9493 last = NULL;
9494 next = xmlXPathNextDescendant;
9495 break;
9496 case AXIS_DESCENDANT_OR_SELF:
9497#ifdef DEBUG_STEP_NTH
9498 xmlGenericError(xmlGenericErrorContext,
9499 "axis 'descendant-or-self' ");
9500#endif
9501 last = NULL;
9502 next = xmlXPathNextDescendantOrSelf;
9503 break;
9504 case AXIS_FOLLOWING:
9505#ifdef DEBUG_STEP_NTH
9506 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9507#endif
9508 last = NULL;
9509 next = xmlXPathNextFollowing;
9510 break;
9511 case AXIS_FOLLOWING_SIBLING:
9512#ifdef DEBUG_STEP_NTH
9513 xmlGenericError(xmlGenericErrorContext,
9514 "axis 'following-siblings' ");
9515#endif
9516 last = NULL;
9517 next = xmlXPathNextFollowingSibling;
9518 break;
9519 case AXIS_NAMESPACE:
9520#ifdef DEBUG_STEP_NTH
9521 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9522#endif
9523 last = NULL;
9524 first = NULL;
9525 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9526 break;
9527 case AXIS_PARENT:
9528#ifdef DEBUG_STEP_NTH
9529 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9530#endif
9531 first = NULL;
9532 next = xmlXPathNextParent;
9533 break;
9534 case AXIS_PRECEDING:
9535#ifdef DEBUG_STEP_NTH
9536 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9537#endif
9538 first = NULL;
9539 next = xmlXPathNextPrecedingInternal;
9540 break;
9541 case AXIS_PRECEDING_SIBLING:
9542#ifdef DEBUG_STEP_NTH
9543 xmlGenericError(xmlGenericErrorContext,
9544 "axis 'preceding-sibling' ");
9545#endif
9546 first = NULL;
9547 next = xmlXPathNextPrecedingSibling;
9548 break;
9549 case AXIS_SELF:
9550#ifdef DEBUG_STEP_NTH
9551 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9552#endif
9553 first = NULL;
9554 last = NULL;
9555 next = xmlXPathNextSelf;
9556 break;
9557 }
9558 if (next == NULL)
9559 return(0);
9560
9561 nodelist = obj->nodesetval;
9562 if (nodelist == NULL) {
9563 xmlXPathFreeObject(obj);
9564 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9565 return(0);
9566 }
9567 addNode = xmlXPathNodeSetAddUnique;
9568#ifdef DEBUG_STEP_NTH
9569 xmlGenericError(xmlGenericErrorContext,
9570 " context contains %d nodes\n", nodelist->nodeNr);
9571 switch (test) {
9572 case NODE_TEST_NONE:
9573 xmlGenericError(xmlGenericErrorContext,
9574 " searching for none !!!\n");
9575 break;
9576 case NODE_TEST_TYPE:
9577 xmlGenericError(xmlGenericErrorContext,
9578 " searching for type %d\n", type);
9579 break;
9580 case NODE_TEST_PI:
9581 xmlGenericError(xmlGenericErrorContext,
9582 " searching for PI !!!\n");
9583 break;
9584 case NODE_TEST_ALL:
9585 xmlGenericError(xmlGenericErrorContext,
9586 " searching for *\n");
9587 break;
9588 case NODE_TEST_NS:
9589 xmlGenericError(xmlGenericErrorContext,
9590 " searching for namespace %s\n",
9591 prefix);
9592 break;
9593 case NODE_TEST_NAME:
9594 xmlGenericError(xmlGenericErrorContext,
9595 " searching for name %s\n", name);
9596 if (prefix != NULL)
9597 xmlGenericError(xmlGenericErrorContext,
9598 " with namespace %s\n", prefix);
9599 break;
9600 }
9601 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9602#endif
9603 /*
9604 * 2.3 Node Tests
9605 * - For the attribute axis, the principal node type is attribute.
9606 * - For the namespace axis, the principal node type is namespace.
9607 * - For other axes, the principal node type is element.
9608 *
9609 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009610 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009611 * select all element children of the context node
9612 */
9613 tmp = ctxt->context->node;
9614 list = xmlXPathNodeSetCreate(NULL);
9615 for (i = 0; i < nodelist->nodeNr; i++) {
9616 ctxt->context->node = nodelist->nodeTab[i];
9617
9618 cur = NULL;
9619 n = 0;
9620 do {
9621 cur = next(ctxt, cur);
9622 if (cur == NULL)
9623 break;
9624 if ((first != NULL) && (*first == cur))
9625 break;
9626 if (((t % 256) == 0) &&
9627 (first != NULL) && (*first != NULL) &&
9628 (xmlXPathCmpNodes(*first, cur) >= 0))
9629 break;
9630 if ((last != NULL) && (*last == cur))
9631 break;
9632 if (((t % 256) == 0) &&
9633 (last != NULL) && (*last != NULL) &&
9634 (xmlXPathCmpNodes(cur, *last) >= 0))
9635 break;
9636 t++;
9637 switch (test) {
9638 case NODE_TEST_NONE:
9639 ctxt->context->node = tmp;
9640 STRANGE return(0);
9641 case NODE_TEST_TYPE:
9642 if ((cur->type == type) ||
9643 ((type == NODE_TYPE_NODE) &&
9644 ((cur->type == XML_DOCUMENT_NODE) ||
9645 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9646 (cur->type == XML_ELEMENT_NODE) ||
9647 (cur->type == XML_PI_NODE) ||
9648 (cur->type == XML_COMMENT_NODE) ||
9649 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009650 (cur->type == XML_TEXT_NODE))) ||
9651 ((type == NODE_TYPE_TEXT) &&
9652 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009653 n++;
9654 if (n == indx)
9655 addNode(list, cur);
9656 }
9657 break;
9658 case NODE_TEST_PI:
9659 if (cur->type == XML_PI_NODE) {
9660 if ((name != NULL) &&
9661 (!xmlStrEqual(name, cur->name)))
9662 break;
9663 n++;
9664 if (n == indx)
9665 addNode(list, cur);
9666 }
9667 break;
9668 case NODE_TEST_ALL:
9669 if (axis == AXIS_ATTRIBUTE) {
9670 if (cur->type == XML_ATTRIBUTE_NODE) {
9671 n++;
9672 if (n == indx)
9673 addNode(list, cur);
9674 }
9675 } else if (axis == AXIS_NAMESPACE) {
9676 if (cur->type == XML_NAMESPACE_DECL) {
9677 n++;
9678 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009679 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9680 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009681 }
9682 } else {
9683 if (cur->type == XML_ELEMENT_NODE) {
9684 if (prefix == NULL) {
9685 n++;
9686 if (n == indx)
9687 addNode(list, cur);
9688 } else if ((cur->ns != NULL) &&
9689 (xmlStrEqual(URI, cur->ns->href))) {
9690 n++;
9691 if (n == indx)
9692 addNode(list, cur);
9693 }
9694 }
9695 }
9696 break;
9697 case NODE_TEST_NS:{
9698 TODO;
9699 break;
9700 }
9701 case NODE_TEST_NAME:
9702 switch (cur->type) {
9703 case XML_ELEMENT_NODE:
9704 if (xmlStrEqual(name, cur->name)) {
9705 if (prefix == NULL) {
9706 if (cur->ns == NULL) {
9707 n++;
9708 if (n == indx)
9709 addNode(list, cur);
9710 }
9711 } else {
9712 if ((cur->ns != NULL) &&
9713 (xmlStrEqual(URI,
9714 cur->ns->href))) {
9715 n++;
9716 if (n == indx)
9717 addNode(list, cur);
9718 }
9719 }
9720 }
9721 break;
9722 case XML_ATTRIBUTE_NODE:{
9723 xmlAttrPtr attr = (xmlAttrPtr) cur;
9724
9725 if (xmlStrEqual(name, attr->name)) {
9726 if (prefix == NULL) {
9727 if ((attr->ns == NULL) ||
9728 (attr->ns->prefix == NULL)) {
9729 n++;
9730 if (n == indx)
9731 addNode(list, cur);
9732 }
9733 } else {
9734 if ((attr->ns != NULL) &&
9735 (xmlStrEqual(URI,
9736 attr->ns->
9737 href))) {
9738 n++;
9739 if (n == indx)
9740 addNode(list, cur);
9741 }
9742 }
9743 }
9744 break;
9745 }
9746 case XML_NAMESPACE_DECL:
9747 if (cur->type == XML_NAMESPACE_DECL) {
9748 xmlNsPtr ns = (xmlNsPtr) cur;
9749
9750 if ((ns->prefix != NULL) && (name != NULL)
9751 && (xmlStrEqual(ns->prefix, name))) {
9752 n++;
9753 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009754 xmlXPathNodeSetAddNs(list,
9755 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009756 }
9757 }
9758 break;
9759 default:
9760 break;
9761 }
9762 break;
9763 break;
9764 }
9765 } while (n < indx);
9766 }
9767 ctxt->context->node = tmp;
9768#ifdef DEBUG_STEP_NTH
9769 xmlGenericError(xmlGenericErrorContext,
9770 "\nExamined %d nodes, found %d nodes at that step\n",
9771 t, list->nodeNr);
9772#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009773 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009774 if ((obj->boolval) && (obj->user != NULL)) {
9775 ctxt->value->boolval = 1;
9776 ctxt->value->user = obj->user;
9777 obj->user = NULL;
9778 obj->boolval = 0;
9779 }
9780 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009781 return(t);
9782}
9783
9784/**
9785 * xmlXPathCompOpEvalFirst:
9786 * @ctxt: the XPath parser context with the compiled expression
9787 * @op: an XPath compiled operation
9788 * @first: the first elem found so far
9789 *
9790 * Evaluate the Precompiled XPath operation searching only the first
9791 * element in document order
9792 *
9793 * Returns the number of examined objects.
9794 */
9795static int
9796xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9797 xmlXPathStepOpPtr op, xmlNodePtr * first)
9798{
9799 int total = 0, cur;
9800 xmlXPathCompExprPtr comp;
9801 xmlXPathObjectPtr arg1, arg2;
9802
Daniel Veillard556c6682001-10-06 09:59:51 +00009803 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009804 comp = ctxt->comp;
9805 switch (op->op) {
9806 case XPATH_OP_END:
9807 return (0);
9808 case XPATH_OP_UNION:
9809 total =
9810 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9811 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009812 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009813 if ((ctxt->value != NULL)
9814 && (ctxt->value->type == XPATH_NODESET)
9815 && (ctxt->value->nodesetval != NULL)
9816 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9817 /*
9818 * limit tree traversing to first node in the result
9819 */
9820 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9821 *first = ctxt->value->nodesetval->nodeTab[0];
9822 }
9823 cur =
9824 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9825 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009826 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009827 CHECK_TYPE0(XPATH_NODESET);
9828 arg2 = valuePop(ctxt);
9829
9830 CHECK_TYPE0(XPATH_NODESET);
9831 arg1 = valuePop(ctxt);
9832
9833 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9834 arg2->nodesetval);
9835 valuePush(ctxt, arg1);
9836 xmlXPathFreeObject(arg2);
9837 /* optimizer */
9838 if (total > cur)
9839 xmlXPathCompSwap(op);
9840 return (total + cur);
9841 case XPATH_OP_ROOT:
9842 xmlXPathRoot(ctxt);
9843 return (0);
9844 case XPATH_OP_NODE:
9845 if (op->ch1 != -1)
9846 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009847 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009848 if (op->ch2 != -1)
9849 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009850 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009851 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9852 return (total);
9853 case XPATH_OP_RESET:
9854 if (op->ch1 != -1)
9855 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009856 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009857 if (op->ch2 != -1)
9858 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009859 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009860 ctxt->context->node = NULL;
9861 return (total);
9862 case XPATH_OP_COLLECT:{
9863 if (op->ch1 == -1)
9864 return (total);
9865
9866 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009867 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009868
9869 /*
9870 * Optimization for [n] selection where n is a number
9871 */
9872 if ((op->ch2 != -1) &&
9873 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9874 (comp->steps[op->ch2].ch1 == -1) &&
9875 (comp->steps[op->ch2].ch2 != -1) &&
9876 (comp->steps[comp->steps[op->ch2].ch2].op ==
9877 XPATH_OP_VALUE)) {
9878 xmlXPathObjectPtr val;
9879
9880 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9881 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9882 int indx = (int) val->floatval;
9883
9884 if (val->floatval == (float) indx) {
9885 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9886 first, NULL);
9887 return (total);
9888 }
9889 }
9890 }
9891 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9892 return (total);
9893 }
9894 case XPATH_OP_VALUE:
9895 valuePush(ctxt,
9896 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9897 return (0);
9898 case XPATH_OP_SORT:
9899 if (op->ch1 != -1)
9900 total +=
9901 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9902 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009903 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009904 if ((ctxt->value != NULL)
9905 && (ctxt->value->type == XPATH_NODESET)
9906 && (ctxt->value->nodesetval != NULL))
9907 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9908 return (total);
9909 default:
9910 return (xmlXPathCompOpEval(ctxt, op));
9911 }
9912}
9913
9914/**
9915 * xmlXPathCompOpEvalLast:
9916 * @ctxt: the XPath parser context with the compiled expression
9917 * @op: an XPath compiled operation
9918 * @last: the last elem found so far
9919 *
9920 * Evaluate the Precompiled XPath operation searching only the last
9921 * element in document order
9922 *
William M. Brack08171912003-12-29 02:52:11 +00009923 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +00009924 */
9925static int
9926xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9927 xmlNodePtr * last)
9928{
9929 int total = 0, cur;
9930 xmlXPathCompExprPtr comp;
9931 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +00009932 xmlNodePtr bak;
9933 xmlDocPtr bakd;
9934 int pp;
9935 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009936
Daniel Veillard556c6682001-10-06 09:59:51 +00009937 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009938 comp = ctxt->comp;
9939 switch (op->op) {
9940 case XPATH_OP_END:
9941 return (0);
9942 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +00009943 bakd = ctxt->context->doc;
9944 bak = ctxt->context->node;
9945 pp = ctxt->context->proximityPosition;
9946 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009947 total =
9948 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009949 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009950 if ((ctxt->value != NULL)
9951 && (ctxt->value->type == XPATH_NODESET)
9952 && (ctxt->value->nodesetval != NULL)
9953 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9954 /*
9955 * limit tree traversing to first node in the result
9956 */
9957 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9958 *last =
9959 ctxt->value->nodesetval->nodeTab[ctxt->value->
9960 nodesetval->nodeNr -
9961 1];
9962 }
William M. Brackce4fc562004-01-22 02:47:18 +00009963 ctxt->context->doc = bakd;
9964 ctxt->context->node = bak;
9965 ctxt->context->proximityPosition = pp;
9966 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009967 cur =
9968 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009969 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009970 if ((ctxt->value != NULL)
9971 && (ctxt->value->type == XPATH_NODESET)
9972 && (ctxt->value->nodesetval != NULL)
9973 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9974 }
9975 CHECK_TYPE0(XPATH_NODESET);
9976 arg2 = valuePop(ctxt);
9977
9978 CHECK_TYPE0(XPATH_NODESET);
9979 arg1 = valuePop(ctxt);
9980
9981 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9982 arg2->nodesetval);
9983 valuePush(ctxt, arg1);
9984 xmlXPathFreeObject(arg2);
9985 /* optimizer */
9986 if (total > cur)
9987 xmlXPathCompSwap(op);
9988 return (total + cur);
9989 case XPATH_OP_ROOT:
9990 xmlXPathRoot(ctxt);
9991 return (0);
9992 case XPATH_OP_NODE:
9993 if (op->ch1 != -1)
9994 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009995 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009996 if (op->ch2 != -1)
9997 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009998 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009999 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10000 return (total);
10001 case XPATH_OP_RESET:
10002 if (op->ch1 != -1)
10003 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010004 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010005 if (op->ch2 != -1)
10006 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010007 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010008 ctxt->context->node = NULL;
10009 return (total);
10010 case XPATH_OP_COLLECT:{
10011 if (op->ch1 == -1)
10012 return (0);
10013
10014 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010015 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010016
10017 /*
10018 * Optimization for [n] selection where n is a number
10019 */
10020 if ((op->ch2 != -1) &&
10021 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10022 (comp->steps[op->ch2].ch1 == -1) &&
10023 (comp->steps[op->ch2].ch2 != -1) &&
10024 (comp->steps[comp->steps[op->ch2].ch2].op ==
10025 XPATH_OP_VALUE)) {
10026 xmlXPathObjectPtr val;
10027
10028 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10029 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10030 int indx = (int) val->floatval;
10031
10032 if (val->floatval == (float) indx) {
10033 total +=
10034 xmlXPathNodeCollectAndTestNth(ctxt, op,
10035 indx, NULL,
10036 last);
10037 return (total);
10038 }
10039 }
10040 }
10041 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10042 return (total);
10043 }
10044 case XPATH_OP_VALUE:
10045 valuePush(ctxt,
10046 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10047 return (0);
10048 case XPATH_OP_SORT:
10049 if (op->ch1 != -1)
10050 total +=
10051 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10052 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010053 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010054 if ((ctxt->value != NULL)
10055 && (ctxt->value->type == XPATH_NODESET)
10056 && (ctxt->value->nodesetval != NULL))
10057 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10058 return (total);
10059 default:
10060 return (xmlXPathCompOpEval(ctxt, op));
10061 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010062}
10063
Owen Taylor3473f882001-02-23 17:55:21 +000010064/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010065 * xmlXPathCompOpEval:
10066 * @ctxt: the XPath parser context with the compiled expression
10067 * @op: an XPath compiled operation
10068 *
10069 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010070 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010071 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010072static int
10073xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10074{
10075 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010076 int equal, ret;
10077 xmlXPathCompExprPtr comp;
10078 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010079 xmlNodePtr bak;
10080 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010081 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010082 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010083
Daniel Veillard556c6682001-10-06 09:59:51 +000010084 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010085 comp = ctxt->comp;
10086 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010087 case XPATH_OP_END:
10088 return (0);
10089 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010090 bakd = ctxt->context->doc;
10091 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010092 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010093 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010094 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010095 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010096 xmlXPathBooleanFunction(ctxt, 1);
10097 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10098 return (total);
10099 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010100 ctxt->context->doc = bakd;
10101 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010102 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010103 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010104 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010105 if (ctxt->error) {
10106 xmlXPathFreeObject(arg2);
10107 return(0);
10108 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010109 xmlXPathBooleanFunction(ctxt, 1);
10110 arg1 = valuePop(ctxt);
10111 arg1->boolval &= arg2->boolval;
10112 valuePush(ctxt, arg1);
10113 xmlXPathFreeObject(arg2);
10114 return (total);
10115 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010116 bakd = ctxt->context->doc;
10117 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010118 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010119 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010120 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010121 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010122 xmlXPathBooleanFunction(ctxt, 1);
10123 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10124 return (total);
10125 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010126 ctxt->context->doc = bakd;
10127 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010128 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010129 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010130 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010131 if (ctxt->error) {
10132 xmlXPathFreeObject(arg2);
10133 return(0);
10134 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010135 xmlXPathBooleanFunction(ctxt, 1);
10136 arg1 = valuePop(ctxt);
10137 arg1->boolval |= arg2->boolval;
10138 valuePush(ctxt, arg1);
10139 xmlXPathFreeObject(arg2);
10140 return (total);
10141 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010142 bakd = ctxt->context->doc;
10143 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010144 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010145 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010146 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010147 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010148 ctxt->context->doc = bakd;
10149 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010150 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010151 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010152 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010153 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010154 if (op->value)
10155 equal = xmlXPathEqualValues(ctxt);
10156 else
10157 equal = xmlXPathNotEqualValues(ctxt);
10158 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010159 return (total);
10160 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010161 bakd = ctxt->context->doc;
10162 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010163 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010164 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010165 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010166 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010167 ctxt->context->doc = bakd;
10168 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010169 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010170 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010171 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010172 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010173 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10174 valuePush(ctxt, xmlXPathNewBoolean(ret));
10175 return (total);
10176 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010177 bakd = ctxt->context->doc;
10178 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010179 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010180 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010181 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010182 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010183 if (op->ch2 != -1) {
10184 ctxt->context->doc = bakd;
10185 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010186 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010187 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010188 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010189 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010190 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010191 if (op->value == 0)
10192 xmlXPathSubValues(ctxt);
10193 else if (op->value == 1)
10194 xmlXPathAddValues(ctxt);
10195 else if (op->value == 2)
10196 xmlXPathValueFlipSign(ctxt);
10197 else if (op->value == 3) {
10198 CAST_TO_NUMBER;
10199 CHECK_TYPE0(XPATH_NUMBER);
10200 }
10201 return (total);
10202 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010203 bakd = ctxt->context->doc;
10204 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010205 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010206 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010207 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010208 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010209 ctxt->context->doc = bakd;
10210 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010211 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010212 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010213 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010214 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010215 if (op->value == 0)
10216 xmlXPathMultValues(ctxt);
10217 else if (op->value == 1)
10218 xmlXPathDivValues(ctxt);
10219 else if (op->value == 2)
10220 xmlXPathModValues(ctxt);
10221 return (total);
10222 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010223 bakd = ctxt->context->doc;
10224 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010225 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010226 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010227 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010228 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010229 ctxt->context->doc = bakd;
10230 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010231 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010232 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010233 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010234 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010235 CHECK_TYPE0(XPATH_NODESET);
10236 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010237
Daniel Veillardf06307e2001-07-03 10:35:50 +000010238 CHECK_TYPE0(XPATH_NODESET);
10239 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010240
Daniel Veillardf06307e2001-07-03 10:35:50 +000010241 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10242 arg2->nodesetval);
10243 valuePush(ctxt, arg1);
10244 xmlXPathFreeObject(arg2);
10245 return (total);
10246 case XPATH_OP_ROOT:
10247 xmlXPathRoot(ctxt);
10248 return (total);
10249 case XPATH_OP_NODE:
10250 if (op->ch1 != -1)
10251 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010252 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010253 if (op->ch2 != -1)
10254 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010255 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010256 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10257 return (total);
10258 case XPATH_OP_RESET:
10259 if (op->ch1 != -1)
10260 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010261 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010262 if (op->ch2 != -1)
10263 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010264 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010265 ctxt->context->node = NULL;
10266 return (total);
10267 case XPATH_OP_COLLECT:{
10268 if (op->ch1 == -1)
10269 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010270
Daniel Veillardf06307e2001-07-03 10:35:50 +000010271 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010272 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010273
Daniel Veillardf06307e2001-07-03 10:35:50 +000010274 /*
10275 * Optimization for [n] selection where n is a number
10276 */
10277 if ((op->ch2 != -1) &&
10278 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10279 (comp->steps[op->ch2].ch1 == -1) &&
10280 (comp->steps[op->ch2].ch2 != -1) &&
10281 (comp->steps[comp->steps[op->ch2].ch2].op ==
10282 XPATH_OP_VALUE)) {
10283 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010284
Daniel Veillardf06307e2001-07-03 10:35:50 +000010285 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10286 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10287 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010288
Daniel Veillardf06307e2001-07-03 10:35:50 +000010289 if (val->floatval == (float) indx) {
10290 total +=
10291 xmlXPathNodeCollectAndTestNth(ctxt, op,
10292 indx, NULL,
10293 NULL);
10294 return (total);
10295 }
10296 }
10297 }
10298 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10299 return (total);
10300 }
10301 case XPATH_OP_VALUE:
10302 valuePush(ctxt,
10303 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10304 return (total);
10305 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010306 xmlXPathObjectPtr val;
10307
Daniel Veillardf06307e2001-07-03 10:35:50 +000010308 if (op->ch1 != -1)
10309 total +=
10310 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010311 if (op->value5 == NULL) {
10312 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10313 if (val == NULL) {
10314 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10315 return(0);
10316 }
10317 valuePush(ctxt, val);
10318 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010319 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010320
Daniel Veillardf06307e2001-07-03 10:35:50 +000010321 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10322 if (URI == NULL) {
10323 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010324 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010325 op->value4, op->value5);
10326 return (total);
10327 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010328 val = xmlXPathVariableLookupNS(ctxt->context,
10329 op->value4, URI);
10330 if (val == NULL) {
10331 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10332 return(0);
10333 }
10334 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010335 }
10336 return (total);
10337 }
10338 case XPATH_OP_FUNCTION:{
10339 xmlXPathFunction func;
10340 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010341 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010342
10343 if (op->ch1 != -1)
10344 total +=
10345 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010346 if (ctxt->valueNr < op->value) {
10347 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010348 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010349 ctxt->error = XPATH_INVALID_OPERAND;
10350 return (total);
10351 }
10352 for (i = 0; i < op->value; i++)
10353 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10354 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010355 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010356 ctxt->error = XPATH_INVALID_OPERAND;
10357 return (total);
10358 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010359 if (op->cache != NULL)
10360 func = (xmlXPathFunction) op->cache;
10361 else {
10362 const xmlChar *URI = NULL;
10363
10364 if (op->value5 == NULL)
10365 func =
10366 xmlXPathFunctionLookup(ctxt->context,
10367 op->value4);
10368 else {
10369 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10370 if (URI == NULL) {
10371 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010372 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010373 op->value4, op->value5);
10374 return (total);
10375 }
10376 func = xmlXPathFunctionLookupNS(ctxt->context,
10377 op->value4, URI);
10378 }
10379 if (func == NULL) {
10380 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010381 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010382 op->value4);
10383 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010384 }
10385 op->cache = (void *) func;
10386 op->cacheURI = (void *) URI;
10387 }
10388 oldFunc = ctxt->context->function;
10389 oldFuncURI = ctxt->context->functionURI;
10390 ctxt->context->function = op->value4;
10391 ctxt->context->functionURI = op->cacheURI;
10392 func(ctxt, op->value);
10393 ctxt->context->function = oldFunc;
10394 ctxt->context->functionURI = oldFuncURI;
10395 return (total);
10396 }
10397 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010398 bakd = ctxt->context->doc;
10399 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010400 if (op->ch1 != -1)
10401 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010402 ctxt->context->doc = bakd;
10403 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010404 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010405 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010406 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010407 ctxt->context->doc = bakd;
10408 ctxt->context->node = bak;
10409 CHECK_ERROR0;
10410 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010411 return (total);
10412 case XPATH_OP_PREDICATE:
10413 case XPATH_OP_FILTER:{
10414 xmlXPathObjectPtr res;
10415 xmlXPathObjectPtr obj, tmp;
10416 xmlNodeSetPtr newset = NULL;
10417 xmlNodeSetPtr oldset;
10418 xmlNodePtr oldnode;
10419 int i;
10420
10421 /*
10422 * Optimization for ()[1] selection i.e. the first elem
10423 */
10424 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10425 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10426 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10427 xmlXPathObjectPtr val;
10428
10429 val = comp->steps[op->ch2].value4;
10430 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10431 (val->floatval == 1.0)) {
10432 xmlNodePtr first = NULL;
10433
10434 total +=
10435 xmlXPathCompOpEvalFirst(ctxt,
10436 &comp->steps[op->ch1],
10437 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010438 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010439 /*
10440 * The nodeset should be in document order,
10441 * Keep only the first value
10442 */
10443 if ((ctxt->value != NULL) &&
10444 (ctxt->value->type == XPATH_NODESET) &&
10445 (ctxt->value->nodesetval != NULL) &&
10446 (ctxt->value->nodesetval->nodeNr > 1))
10447 ctxt->value->nodesetval->nodeNr = 1;
10448 return (total);
10449 }
10450 }
10451 /*
10452 * Optimization for ()[last()] selection i.e. the last elem
10453 */
10454 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10455 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10456 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10457 int f = comp->steps[op->ch2].ch1;
10458
10459 if ((f != -1) &&
10460 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10461 (comp->steps[f].value5 == NULL) &&
10462 (comp->steps[f].value == 0) &&
10463 (comp->steps[f].value4 != NULL) &&
10464 (xmlStrEqual
10465 (comp->steps[f].value4, BAD_CAST "last"))) {
10466 xmlNodePtr last = NULL;
10467
10468 total +=
10469 xmlXPathCompOpEvalLast(ctxt,
10470 &comp->steps[op->ch1],
10471 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010472 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010473 /*
10474 * The nodeset should be in document order,
10475 * Keep only the last value
10476 */
10477 if ((ctxt->value != NULL) &&
10478 (ctxt->value->type == XPATH_NODESET) &&
10479 (ctxt->value->nodesetval != NULL) &&
10480 (ctxt->value->nodesetval->nodeTab != NULL) &&
10481 (ctxt->value->nodesetval->nodeNr > 1)) {
10482 ctxt->value->nodesetval->nodeTab[0] =
10483 ctxt->value->nodesetval->nodeTab[ctxt->
10484 value->
10485 nodesetval->
10486 nodeNr -
10487 1];
10488 ctxt->value->nodesetval->nodeNr = 1;
10489 }
10490 return (total);
10491 }
10492 }
10493
10494 if (op->ch1 != -1)
10495 total +=
10496 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010497 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010498 if (op->ch2 == -1)
10499 return (total);
10500 if (ctxt->value == NULL)
10501 return (total);
10502
10503 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010504
10505#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010506 /*
10507 * Hum are we filtering the result of an XPointer expression
10508 */
10509 if (ctxt->value->type == XPATH_LOCATIONSET) {
10510 xmlLocationSetPtr newlocset = NULL;
10511 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010512
Daniel Veillardf06307e2001-07-03 10:35:50 +000010513 /*
10514 * Extract the old locset, and then evaluate the result of the
10515 * expression for all the element in the locset. use it to grow
10516 * up a new locset.
10517 */
10518 CHECK_TYPE0(XPATH_LOCATIONSET);
10519 obj = valuePop(ctxt);
10520 oldlocset = obj->user;
10521 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010522
Daniel Veillardf06307e2001-07-03 10:35:50 +000010523 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10524 ctxt->context->contextSize = 0;
10525 ctxt->context->proximityPosition = 0;
10526 if (op->ch2 != -1)
10527 total +=
10528 xmlXPathCompOpEval(ctxt,
10529 &comp->steps[op->ch2]);
10530 res = valuePop(ctxt);
10531 if (res != NULL)
10532 xmlXPathFreeObject(res);
10533 valuePush(ctxt, obj);
10534 CHECK_ERROR0;
10535 return (total);
10536 }
10537 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010538
Daniel Veillardf06307e2001-07-03 10:35:50 +000010539 for (i = 0; i < oldlocset->locNr; i++) {
10540 /*
10541 * Run the evaluation with a node list made of a
10542 * single item in the nodelocset.
10543 */
10544 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010545 ctxt->context->contextSize = oldlocset->locNr;
10546 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010547 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10548 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010549
Daniel Veillardf06307e2001-07-03 10:35:50 +000010550 if (op->ch2 != -1)
10551 total +=
10552 xmlXPathCompOpEval(ctxt,
10553 &comp->steps[op->ch2]);
10554 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010555
Daniel Veillardf06307e2001-07-03 10:35:50 +000010556 /*
10557 * The result of the evaluation need to be tested to
10558 * decided whether the filter succeeded or not
10559 */
10560 res = valuePop(ctxt);
10561 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10562 xmlXPtrLocationSetAdd(newlocset,
10563 xmlXPathObjectCopy
10564 (oldlocset->locTab[i]));
10565 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010566
Daniel Veillardf06307e2001-07-03 10:35:50 +000010567 /*
10568 * Cleanup
10569 */
10570 if (res != NULL)
10571 xmlXPathFreeObject(res);
10572 if (ctxt->value == tmp) {
10573 res = valuePop(ctxt);
10574 xmlXPathFreeObject(res);
10575 }
10576
10577 ctxt->context->node = NULL;
10578 }
10579
10580 /*
10581 * The result is used as the new evaluation locset.
10582 */
10583 xmlXPathFreeObject(obj);
10584 ctxt->context->node = NULL;
10585 ctxt->context->contextSize = -1;
10586 ctxt->context->proximityPosition = -1;
10587 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10588 ctxt->context->node = oldnode;
10589 return (total);
10590 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010591#endif /* LIBXML_XPTR_ENABLED */
10592
Daniel Veillardf06307e2001-07-03 10:35:50 +000010593 /*
10594 * Extract the old set, and then evaluate the result of the
10595 * expression for all the element in the set. use it to grow
10596 * up a new set.
10597 */
10598 CHECK_TYPE0(XPATH_NODESET);
10599 obj = valuePop(ctxt);
10600 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010601
Daniel Veillardf06307e2001-07-03 10:35:50 +000010602 oldnode = ctxt->context->node;
10603 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010604
Daniel Veillardf06307e2001-07-03 10:35:50 +000010605 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10606 ctxt->context->contextSize = 0;
10607 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000010608/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000010609 if (op->ch2 != -1)
10610 total +=
10611 xmlXPathCompOpEval(ctxt,
10612 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010613 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010614 res = valuePop(ctxt);
10615 if (res != NULL)
10616 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000010617*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000010618 valuePush(ctxt, obj);
10619 ctxt->context->node = oldnode;
10620 CHECK_ERROR0;
10621 } else {
10622 /*
10623 * Initialize the new set.
10624 */
10625 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010626
Daniel Veillardf06307e2001-07-03 10:35:50 +000010627 for (i = 0; i < oldset->nodeNr; i++) {
10628 /*
10629 * Run the evaluation with a node list made of
10630 * a single item in the nodeset.
10631 */
10632 ctxt->context->node = oldset->nodeTab[i];
10633 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10634 valuePush(ctxt, tmp);
10635 ctxt->context->contextSize = oldset->nodeNr;
10636 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010637
Daniel Veillardf06307e2001-07-03 10:35:50 +000010638 if (op->ch2 != -1)
10639 total +=
10640 xmlXPathCompOpEval(ctxt,
10641 &comp->steps[op->ch2]);
10642 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010643
Daniel Veillardf06307e2001-07-03 10:35:50 +000010644 /*
William M. Brack08171912003-12-29 02:52:11 +000010645 * The result of the evaluation needs to be tested to
10646 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010647 */
10648 res = valuePop(ctxt);
10649 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10650 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10651 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010652
Daniel Veillardf06307e2001-07-03 10:35:50 +000010653 /*
10654 * Cleanup
10655 */
10656 if (res != NULL)
10657 xmlXPathFreeObject(res);
10658 if (ctxt->value == tmp) {
10659 res = valuePop(ctxt);
10660 xmlXPathFreeObject(res);
10661 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010662
Daniel Veillardf06307e2001-07-03 10:35:50 +000010663 ctxt->context->node = NULL;
10664 }
10665
10666 /*
10667 * The result is used as the new evaluation set.
10668 */
10669 xmlXPathFreeObject(obj);
10670 ctxt->context->node = NULL;
10671 ctxt->context->contextSize = -1;
10672 ctxt->context->proximityPosition = -1;
10673 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10674 }
10675 ctxt->context->node = oldnode;
10676 return (total);
10677 }
10678 case XPATH_OP_SORT:
10679 if (op->ch1 != -1)
10680 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010681 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010682 if ((ctxt->value != NULL) &&
10683 (ctxt->value->type == XPATH_NODESET) &&
10684 (ctxt->value->nodesetval != NULL))
10685 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10686 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010687#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010688 case XPATH_OP_RANGETO:{
10689 xmlXPathObjectPtr range;
10690 xmlXPathObjectPtr res, obj;
10691 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010692 xmlLocationSetPtr newlocset = NULL;
10693 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010694 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000010695 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010696
Daniel Veillardf06307e2001-07-03 10:35:50 +000010697 if (op->ch1 != -1)
10698 total +=
10699 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10700 if (op->ch2 == -1)
10701 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010702
William M. Brack08171912003-12-29 02:52:11 +000010703 if (ctxt->value->type == XPATH_LOCATIONSET) {
10704 /*
10705 * Extract the old locset, and then evaluate the result of the
10706 * expression for all the element in the locset. use it to grow
10707 * up a new locset.
10708 */
10709 CHECK_TYPE0(XPATH_LOCATIONSET);
10710 obj = valuePop(ctxt);
10711 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010712
William M. Brack08171912003-12-29 02:52:11 +000010713 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000010714 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000010715 ctxt->context->contextSize = 0;
10716 ctxt->context->proximityPosition = 0;
10717 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10718 res = valuePop(ctxt);
10719 if (res != NULL)
10720 xmlXPathFreeObject(res);
10721 valuePush(ctxt, obj);
10722 CHECK_ERROR0;
10723 return (total);
10724 }
10725 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010726
William M. Brack08171912003-12-29 02:52:11 +000010727 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010728 /*
William M. Brack08171912003-12-29 02:52:11 +000010729 * Run the evaluation with a node list made of a
10730 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010731 */
William M. Brackf7eb7942003-12-31 07:59:17 +000010732 ctxt->context->node = oldlocset->locTab[i]->user;
10733 ctxt->context->contextSize = oldlocset->locNr;
10734 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010735 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10736 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010737
Daniel Veillardf06307e2001-07-03 10:35:50 +000010738 if (op->ch2 != -1)
10739 total +=
10740 xmlXPathCompOpEval(ctxt,
10741 &comp->steps[op->ch2]);
10742 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010743
Daniel Veillardf06307e2001-07-03 10:35:50 +000010744 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000010745 if (res->type == XPATH_LOCATIONSET) {
10746 xmlLocationSetPtr rloc =
10747 (xmlLocationSetPtr)res->user;
10748 for (j=0; j<rloc->locNr; j++) {
10749 range = xmlXPtrNewRange(
10750 oldlocset->locTab[i]->user,
10751 oldlocset->locTab[i]->index,
10752 rloc->locTab[j]->user2,
10753 rloc->locTab[j]->index2);
10754 if (range != NULL) {
10755 xmlXPtrLocationSetAdd(newlocset, range);
10756 }
10757 }
10758 } else {
10759 range = xmlXPtrNewRangeNodeObject(
10760 (xmlNodePtr)oldlocset->locTab[i]->user, res);
10761 if (range != NULL) {
10762 xmlXPtrLocationSetAdd(newlocset,range);
10763 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010764 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010765
Daniel Veillardf06307e2001-07-03 10:35:50 +000010766 /*
10767 * Cleanup
10768 */
10769 if (res != NULL)
10770 xmlXPathFreeObject(res);
10771 if (ctxt->value == tmp) {
10772 res = valuePop(ctxt);
10773 xmlXPathFreeObject(res);
10774 }
10775
10776 ctxt->context->node = NULL;
10777 }
William M. Brack72ee48d2003-12-30 08:30:19 +000010778 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000010779 CHECK_TYPE0(XPATH_NODESET);
10780 obj = valuePop(ctxt);
10781 oldset = obj->nodesetval;
10782 ctxt->context->node = NULL;
10783
10784 newlocset = xmlXPtrLocationSetCreate(NULL);
10785
10786 if (oldset != NULL) {
10787 for (i = 0; i < oldset->nodeNr; i++) {
10788 /*
10789 * Run the evaluation with a node list made of a single item
10790 * in the nodeset.
10791 */
10792 ctxt->context->node = oldset->nodeTab[i];
10793 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10794 valuePush(ctxt, tmp);
10795
10796 if (op->ch2 != -1)
10797 total +=
10798 xmlXPathCompOpEval(ctxt,
10799 &comp->steps[op->ch2]);
10800 CHECK_ERROR0;
10801
William M. Brack08171912003-12-29 02:52:11 +000010802 res = valuePop(ctxt);
10803 range =
10804 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10805 res);
10806 if (range != NULL) {
10807 xmlXPtrLocationSetAdd(newlocset, range);
10808 }
10809
10810 /*
10811 * Cleanup
10812 */
10813 if (res != NULL)
10814 xmlXPathFreeObject(res);
10815 if (ctxt->value == tmp) {
10816 res = valuePop(ctxt);
10817 xmlXPathFreeObject(res);
10818 }
10819
10820 ctxt->context->node = NULL;
10821 }
10822 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010823 }
10824
10825 /*
10826 * The result is used as the new evaluation set.
10827 */
10828 xmlXPathFreeObject(obj);
10829 ctxt->context->node = NULL;
10830 ctxt->context->contextSize = -1;
10831 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010832 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010833 return (total);
10834 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010835#endif /* LIBXML_XPTR_ENABLED */
10836 }
10837 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010838 "XPath: unknown precompiled operation %d\n", op->op);
10839 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010840}
10841
10842/**
10843 * xmlXPathRunEval:
10844 * @ctxt: the XPath parser context with the compiled expression
10845 *
10846 * Evaluate the Precompiled XPath expression in the given context.
10847 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010848static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010849xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10850 xmlXPathCompExprPtr comp;
10851
10852 if ((ctxt == NULL) || (ctxt->comp == NULL))
10853 return;
10854
10855 if (ctxt->valueTab == NULL) {
10856 /* Allocate the value stack */
10857 ctxt->valueTab = (xmlXPathObjectPtr *)
10858 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10859 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010860 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010861 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010862 }
10863 ctxt->valueNr = 0;
10864 ctxt->valueMax = 10;
10865 ctxt->value = NULL;
10866 }
10867 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010868 if(comp->last < 0) {
10869 xmlGenericError(xmlGenericErrorContext,
10870 "xmlXPathRunEval: last is less than zero\n");
10871 return;
10872 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010873 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10874}
10875
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010876/************************************************************************
10877 * *
10878 * Public interfaces *
10879 * *
10880 ************************************************************************/
10881
10882/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010883 * xmlXPathEvalPredicate:
10884 * @ctxt: the XPath context
10885 * @res: the Predicate Expression evaluation result
10886 *
10887 * Evaluate a predicate result for the current node.
10888 * A PredicateExpr is evaluated by evaluating the Expr and converting
10889 * the result to a boolean. If the result is a number, the result will
10890 * be converted to true if the number is equal to the position of the
10891 * context node in the context node list (as returned by the position
10892 * function) and will be converted to false otherwise; if the result
10893 * is not a number, then the result will be converted as if by a call
10894 * to the boolean function.
10895 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010896 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010897 */
10898int
10899xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10900 if (res == NULL) return(0);
10901 switch (res->type) {
10902 case XPATH_BOOLEAN:
10903 return(res->boolval);
10904 case XPATH_NUMBER:
10905 return(res->floatval == ctxt->proximityPosition);
10906 case XPATH_NODESET:
10907 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010908 if (res->nodesetval == NULL)
10909 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010910 return(res->nodesetval->nodeNr != 0);
10911 case XPATH_STRING:
10912 return((res->stringval != NULL) &&
10913 (xmlStrlen(res->stringval) != 0));
10914 default:
10915 STRANGE
10916 }
10917 return(0);
10918}
10919
10920/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010921 * xmlXPathEvaluatePredicateResult:
10922 * @ctxt: the XPath Parser context
10923 * @res: the Predicate Expression evaluation result
10924 *
10925 * Evaluate a predicate result for the current node.
10926 * A PredicateExpr is evaluated by evaluating the Expr and converting
10927 * the result to a boolean. If the result is a number, the result will
10928 * be converted to true if the number is equal to the position of the
10929 * context node in the context node list (as returned by the position
10930 * function) and will be converted to false otherwise; if the result
10931 * is not a number, then the result will be converted as if by a call
10932 * to the boolean function.
10933 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010934 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010935 */
10936int
10937xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10938 xmlXPathObjectPtr res) {
10939 if (res == NULL) return(0);
10940 switch (res->type) {
10941 case XPATH_BOOLEAN:
10942 return(res->boolval);
10943 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000010944#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000010945 return((res->floatval == ctxt->context->proximityPosition) &&
10946 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000010947#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010948 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000010949#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010950 case XPATH_NODESET:
10951 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010952 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010953 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010954 return(res->nodesetval->nodeNr != 0);
10955 case XPATH_STRING:
10956 return((res->stringval != NULL) &&
10957 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000010958#ifdef LIBXML_XPTR_ENABLED
10959 case XPATH_LOCATIONSET:{
10960 xmlLocationSetPtr ptr = res->user;
10961 if (ptr == NULL)
10962 return(0);
10963 return (ptr->locNr != 0);
10964 }
10965#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010966 default:
10967 STRANGE
10968 }
10969 return(0);
10970}
10971
10972/**
Daniel Veillard4773df22004-01-23 13:15:13 +000010973 * xmlXPathCtxtCompile:
10974 * @ctxt: an XPath context
10975 * @str: the XPath expression
10976 *
10977 * Compile an XPath expression
10978 *
10979 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
10980 * the caller has to free the object.
10981 */
10982xmlXPathCompExprPtr
10983xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
10984 xmlXPathParserContextPtr pctxt;
10985 xmlXPathCompExprPtr comp;
10986
10987 xmlXPathInit();
10988
10989 pctxt = xmlXPathNewParserContext(str, ctxt);
10990 xmlXPathCompileExpr(pctxt);
10991
10992 if( pctxt->error != XPATH_EXPRESSION_OK )
10993 {
10994 xmlXPathFreeParserContext(pctxt);
10995 return (0);
10996 }
10997
10998 if (*pctxt->cur != 0) {
10999 /*
11000 * aleksey: in some cases this line prints *second* error message
11001 * (see bug #78858) and probably this should be fixed.
11002 * However, we are not sure that all error messages are printed
11003 * out in other places. It's not critical so we leave it as-is for now
11004 */
11005 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11006 comp = NULL;
11007 } else {
11008 comp = pctxt->comp;
11009 pctxt->comp = NULL;
11010 }
11011 xmlXPathFreeParserContext(pctxt);
11012 if (comp != NULL) {
11013 comp->expr = xmlStrdup(str);
11014#ifdef DEBUG_EVAL_COUNTS
11015 comp->string = xmlStrdup(str);
11016 comp->nb = 0;
11017#endif
11018 }
11019 return(comp);
11020}
11021
11022/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011023 * xmlXPathCompile:
11024 * @str: the XPath expression
11025 *
11026 * Compile an XPath expression
11027 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000011028 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011029 * the caller has to free the object.
11030 */
11031xmlXPathCompExprPtr
11032xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000011033 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011034}
11035
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011036/**
11037 * xmlXPathCompiledEval:
11038 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000011039 * @ctx: the XPath context
11040 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011041 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000011042 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011043 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000011044 * the caller has to free the object.
11045 */
11046xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011047xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000011048 xmlXPathParserContextPtr ctxt;
11049 xmlXPathObjectPtr res, tmp, init = NULL;
11050 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000011051#ifndef LIBXML_THREAD_ENABLED
11052 static int reentance = 0;
11053#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011054
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011055 if ((comp == NULL) || (ctx == NULL))
11056 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011057 xmlXPathInit();
11058
11059 CHECK_CONTEXT(ctx)
11060
Daniel Veillard81463942001-10-16 12:34:39 +000011061#ifndef LIBXML_THREAD_ENABLED
11062 reentance++;
11063 if (reentance > 1)
11064 xmlXPathDisableOptimizer = 1;
11065#endif
11066
Daniel Veillardf06307e2001-07-03 10:35:50 +000011067#ifdef DEBUG_EVAL_COUNTS
11068 comp->nb++;
11069 if ((comp->string != NULL) && (comp->nb > 100)) {
11070 fprintf(stderr, "100 x %s\n", comp->string);
11071 comp->nb = 0;
11072 }
11073#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011074 ctxt = xmlXPathCompParserContext(comp, ctx);
11075 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011076
11077 if (ctxt->value == NULL) {
11078 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011079 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011080 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011081 } else {
11082 res = valuePop(ctxt);
11083 }
11084
Daniel Veillardf06307e2001-07-03 10:35:50 +000011085
Owen Taylor3473f882001-02-23 17:55:21 +000011086 do {
11087 tmp = valuePop(ctxt);
11088 if (tmp != NULL) {
11089 if (tmp != init)
11090 stack++;
11091 xmlXPathFreeObject(tmp);
11092 }
11093 } while (tmp != NULL);
11094 if ((stack != 0) && (res != NULL)) {
11095 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011096 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011097 stack);
11098 }
11099 if (ctxt->error != XPATH_EXPRESSION_OK) {
11100 xmlXPathFreeObject(res);
11101 res = NULL;
11102 }
11103
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011104
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011105 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011106 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011107#ifndef LIBXML_THREAD_ENABLED
11108 reentance--;
11109#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011110 return(res);
11111}
11112
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011113/**
11114 * xmlXPathEvalExpr:
11115 * @ctxt: the XPath Parser context
11116 *
11117 * Parse and evaluate an XPath expression in the given context,
11118 * then push the result on the context stack
11119 */
11120void
11121xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
11122 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011123 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011124 xmlXPathRunEval(ctxt);
11125}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011126
11127/**
11128 * xmlXPathEval:
11129 * @str: the XPath expression
11130 * @ctx: the XPath context
11131 *
11132 * Evaluate the XPath Location Path in the given context.
11133 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011134 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011135 * the caller has to free the object.
11136 */
11137xmlXPathObjectPtr
11138xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11139 xmlXPathParserContextPtr ctxt;
11140 xmlXPathObjectPtr res, tmp, init = NULL;
11141 int stack = 0;
11142
11143 xmlXPathInit();
11144
11145 CHECK_CONTEXT(ctx)
11146
11147 ctxt = xmlXPathNewParserContext(str, ctx);
11148 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011149
11150 if (ctxt->value == NULL) {
11151 xmlGenericError(xmlGenericErrorContext,
11152 "xmlXPathEval: evaluation failed\n");
11153 res = NULL;
11154 } else if (*ctxt->cur != 0) {
11155 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11156 res = NULL;
11157 } else {
11158 res = valuePop(ctxt);
11159 }
11160
11161 do {
11162 tmp = valuePop(ctxt);
11163 if (tmp != NULL) {
11164 if (tmp != init)
11165 stack++;
11166 xmlXPathFreeObject(tmp);
11167 }
11168 } while (tmp != NULL);
11169 if ((stack != 0) && (res != NULL)) {
11170 xmlGenericError(xmlGenericErrorContext,
11171 "xmlXPathEval: %d object left on the stack\n",
11172 stack);
11173 }
11174 if (ctxt->error != XPATH_EXPRESSION_OK) {
11175 xmlXPathFreeObject(res);
11176 res = NULL;
11177 }
11178
Owen Taylor3473f882001-02-23 17:55:21 +000011179 xmlXPathFreeParserContext(ctxt);
11180 return(res);
11181}
11182
11183/**
11184 * xmlXPathEvalExpression:
11185 * @str: the XPath expression
11186 * @ctxt: the XPath context
11187 *
11188 * Evaluate the XPath expression in the given context.
11189 *
11190 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11191 * the caller has to free the object.
11192 */
11193xmlXPathObjectPtr
11194xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11195 xmlXPathParserContextPtr pctxt;
11196 xmlXPathObjectPtr res, tmp;
11197 int stack = 0;
11198
11199 xmlXPathInit();
11200
11201 CHECK_CONTEXT(ctxt)
11202
11203 pctxt = xmlXPathNewParserContext(str, ctxt);
11204 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011205
11206 if (*pctxt->cur != 0) {
11207 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11208 res = NULL;
11209 } else {
11210 res = valuePop(pctxt);
11211 }
11212 do {
11213 tmp = valuePop(pctxt);
11214 if (tmp != NULL) {
11215 xmlXPathFreeObject(tmp);
11216 stack++;
11217 }
11218 } while (tmp != NULL);
11219 if ((stack != 0) && (res != NULL)) {
11220 xmlGenericError(xmlGenericErrorContext,
11221 "xmlXPathEvalExpression: %d object left on the stack\n",
11222 stack);
11223 }
11224 xmlXPathFreeParserContext(pctxt);
11225 return(res);
11226}
11227
Daniel Veillard42766c02002-08-22 20:52:17 +000011228/************************************************************************
11229 * *
11230 * Extra functions not pertaining to the XPath spec *
11231 * *
11232 ************************************************************************/
11233/**
11234 * xmlXPathEscapeUriFunction:
11235 * @ctxt: the XPath Parser context
11236 * @nargs: the number of arguments
11237 *
11238 * Implement the escape-uri() XPath function
11239 * string escape-uri(string $str, bool $escape-reserved)
11240 *
11241 * This function applies the URI escaping rules defined in section 2 of [RFC
11242 * 2396] to the string supplied as $uri-part, which typically represents all
11243 * or part of a URI. The effect of the function is to replace any special
11244 * character in the string by an escape sequence of the form %xx%yy...,
11245 * where xxyy... is the hexadecimal representation of the octets used to
11246 * represent the character in UTF-8.
11247 *
11248 * The set of characters that are escaped depends on the setting of the
11249 * boolean argument $escape-reserved.
11250 *
11251 * If $escape-reserved is true, all characters are escaped other than lower
11252 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11253 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11254 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11255 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11256 * A-F).
11257 *
11258 * If $escape-reserved is false, the behavior differs in that characters
11259 * referred to in [RFC 2396] as reserved characters are not escaped. These
11260 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11261 *
11262 * [RFC 2396] does not define whether escaped URIs should use lower case or
11263 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11264 * compared using string comparison functions, this function must always use
11265 * the upper-case letters A-F.
11266 *
11267 * Generally, $escape-reserved should be set to true when escaping a string
11268 * that is to form a single part of a URI, and to false when escaping an
11269 * entire URI or URI reference.
11270 *
11271 * In the case of non-ascii characters, the string is encoded according to
11272 * utf-8 and then converted according to RFC 2396.
11273 *
11274 * Examples
11275 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11276 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11277 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11278 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11279 *
11280 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011281static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011282xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11283 xmlXPathObjectPtr str;
11284 int escape_reserved;
11285 xmlBufferPtr target;
11286 xmlChar *cptr;
11287 xmlChar escape[4];
11288
11289 CHECK_ARITY(2);
11290
11291 escape_reserved = xmlXPathPopBoolean(ctxt);
11292
11293 CAST_TO_STRING;
11294 str = valuePop(ctxt);
11295
11296 target = xmlBufferCreate();
11297
11298 escape[0] = '%';
11299 escape[3] = 0;
11300
11301 if (target) {
11302 for (cptr = str->stringval; *cptr; cptr++) {
11303 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11304 (*cptr >= 'a' && *cptr <= 'z') ||
11305 (*cptr >= '0' && *cptr <= '9') ||
11306 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11307 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11308 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11309 (*cptr == '%' &&
11310 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11311 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11312 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11313 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11314 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11315 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11316 (!escape_reserved &&
11317 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11318 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11319 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11320 *cptr == ','))) {
11321 xmlBufferAdd(target, cptr, 1);
11322 } else {
11323 if ((*cptr >> 4) < 10)
11324 escape[1] = '0' + (*cptr >> 4);
11325 else
11326 escape[1] = 'A' - 10 + (*cptr >> 4);
11327 if ((*cptr & 0xF) < 10)
11328 escape[2] = '0' + (*cptr & 0xF);
11329 else
11330 escape[2] = 'A' - 10 + (*cptr & 0xF);
11331
11332 xmlBufferAdd(target, &escape[0], 3);
11333 }
11334 }
11335 }
11336 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11337 xmlBufferFree(target);
11338 xmlXPathFreeObject(str);
11339}
11340
Owen Taylor3473f882001-02-23 17:55:21 +000011341/**
11342 * xmlXPathRegisterAllFunctions:
11343 * @ctxt: the XPath context
11344 *
11345 * Registers all default XPath functions in this context
11346 */
11347void
11348xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11349{
11350 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11351 xmlXPathBooleanFunction);
11352 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11353 xmlXPathCeilingFunction);
11354 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11355 xmlXPathCountFunction);
11356 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11357 xmlXPathConcatFunction);
11358 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11359 xmlXPathContainsFunction);
11360 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11361 xmlXPathIdFunction);
11362 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11363 xmlXPathFalseFunction);
11364 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11365 xmlXPathFloorFunction);
11366 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11367 xmlXPathLastFunction);
11368 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11369 xmlXPathLangFunction);
11370 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11371 xmlXPathLocalNameFunction);
11372 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11373 xmlXPathNotFunction);
11374 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11375 xmlXPathNameFunction);
11376 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11377 xmlXPathNamespaceURIFunction);
11378 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11379 xmlXPathNormalizeFunction);
11380 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11381 xmlXPathNumberFunction);
11382 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11383 xmlXPathPositionFunction);
11384 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11385 xmlXPathRoundFunction);
11386 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11387 xmlXPathStringFunction);
11388 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11389 xmlXPathStringLengthFunction);
11390 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11391 xmlXPathStartsWithFunction);
11392 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11393 xmlXPathSubstringFunction);
11394 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11395 xmlXPathSubstringBeforeFunction);
11396 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11397 xmlXPathSubstringAfterFunction);
11398 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11399 xmlXPathSumFunction);
11400 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11401 xmlXPathTrueFunction);
11402 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11403 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011404
11405 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11406 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11407 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011408}
11409
11410#endif /* LIBXML_XPATH_ENABLED */