blob: 2a7bb32c09629114a69769cda955104d8eb9f595 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
Owen Taylor3473f882001-02-23 17:55:21 +000031#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000034#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000035#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#endif
Owen Taylor3473f882001-02-23 17:55:21 +000037
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000052#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000053#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000054
Daniel Veillardd96f6d32003-10-07 21:25:12 +000055#define TODO \
56 xmlGenericError(xmlGenericErrorContext, \
57 "Unimplemented block at %s:%d\n", \
58 __FILE__, __LINE__);
59
William M. Brackd1757ab2004-10-02 22:07:48 +000060/*
61 * TODO:
62 * There are a few spots where some tests are done which depend upon ascii
63 * data. These should be enhanced for full UTF8 support (see particularly
64 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
65 */
66
Daniel Veillard4432df22003-09-28 18:58:27 +000067#if defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000068/************************************************************************
69 * *
70 * Floating point stuff *
71 * *
72 ************************************************************************/
73
Daniel Veillardc0631a62001-09-20 13:56:06 +000074#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000075#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000076#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000077#include "trionan.c"
78
Owen Taylor3473f882001-02-23 17:55:21 +000079/*
Owen Taylor3473f882001-02-23 17:55:21 +000080 * The lack of portability of this section of the libc is annoying !
81 */
82double xmlXPathNAN = 0;
83double xmlXPathPINF = 1;
84double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000085double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000086static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000087
Owen Taylor3473f882001-02-23 17:55:21 +000088/**
89 * xmlXPathInit:
90 *
91 * Initialize the XPath environment
92 */
93void
94xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +000095 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +000096
Bjorn Reese45029602001-08-21 09:23:53 +000097 xmlXPathPINF = trio_pinf();
98 xmlXPathNINF = trio_ninf();
99 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000100 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000101
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000102 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000103}
104
Daniel Veillardcda96922001-08-21 10:56:31 +0000105/**
106 * xmlXPathIsNaN:
107 * @val: a double value
108 *
109 * Provides a portable isnan() function to detect whether a double
110 * is a NotaNumber. Based on trio code
111 * http://sourceforge.net/projects/ctrio/
112 *
113 * Returns 1 if the value is a NaN, 0 otherwise
114 */
115int
116xmlXPathIsNaN(double val) {
117 return(trio_isnan(val));
118}
119
120/**
121 * xmlXPathIsInf:
122 * @val: a double value
123 *
124 * Provides a portable isinf() function to detect whether a double
125 * is a +Infinite or -Infinite. Based on trio code
126 * http://sourceforge.net/projects/ctrio/
127 *
128 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
129 */
130int
131xmlXPathIsInf(double val) {
132 return(trio_isinf(val));
133}
134
Daniel Veillard4432df22003-09-28 18:58:27 +0000135#endif /* SCHEMAS or XPATH */
136#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000137/**
138 * xmlXPathGetSign:
139 * @val: a double value
140 *
141 * Provides a portable function to detect the sign of a double
142 * Modified from trio code
143 * http://sourceforge.net/projects/ctrio/
144 *
145 * Returns 1 if the value is Negative, 0 if positive
146 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000147static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000148xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000149 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000150}
151
152
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000153/*
154 * TODO: when compatibility allows remove all "fake node libxslt" strings
155 * the test should just be name[0] = ' '
156 */
157/* #define DEBUG */
158/* #define DEBUG_STEP */
159/* #define DEBUG_STEP_NTH */
160/* #define DEBUG_EXPR */
161/* #define DEBUG_EVAL_COUNTS */
162
163static xmlNs xmlXPathXMLNamespaceStruct = {
164 NULL,
165 XML_NAMESPACE_DECL,
166 XML_XML_NAMESPACE,
167 BAD_CAST "xml",
168 NULL
169};
170static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
171#ifndef LIBXML_THREAD_ENABLED
172/*
173 * Optimizer is disabled only when threaded apps are detected while
174 * the library ain't compiled for thread safety.
175 */
176static int xmlXPathDisableOptimizer = 0;
177#endif
178
Owen Taylor3473f882001-02-23 17:55:21 +0000179/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000180 * *
181 * Error handling routines *
182 * *
183 ************************************************************************/
184
William M. Brack08171912003-12-29 02:52:11 +0000185/*
186 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
187 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000188static const char *xmlXPathErrorMessages[] = {
189 "Ok\n",
190 "Number encoding\n",
191 "Unfinished literal\n",
192 "Start of literal\n",
193 "Expected $ for variable reference\n",
194 "Undefined variable\n",
195 "Invalid predicate\n",
196 "Invalid expression\n",
197 "Missing closing curly brace\n",
198 "Unregistered function\n",
199 "Invalid operand\n",
200 "Invalid type\n",
201 "Invalid number of arguments\n",
202 "Invalid context size\n",
203 "Invalid context position\n",
204 "Memory allocation error\n",
205 "Syntax error\n",
206 "Resource error\n",
207 "Sub resource error\n",
208 "Undefined namespace prefix\n",
209 "Encoding error\n",
210 "Char out of XML range\n"
211};
212
213
214/**
215 * xmlXPathErrMemory:
216 * @ctxt: an XPath context
217 * @extra: extra informations
218 *
219 * Handle a redefinition of attribute error
220 */
221static void
222xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
223{
224 if (ctxt != NULL) {
225 if (extra) {
226 xmlChar buf[200];
227
228 xmlStrPrintf(buf, 200,
229 BAD_CAST "Memory allocation failed : %s\n",
230 extra);
231 ctxt->lastError.message = (char *) xmlStrdup(buf);
232 } else {
233 ctxt->lastError.message = (char *)
234 xmlStrdup(BAD_CAST "Memory allocation failed\n");
235 }
236 ctxt->lastError.domain = XML_FROM_XPATH;
237 ctxt->lastError.code = XML_ERR_NO_MEMORY;
238 if (ctxt->error != NULL)
239 ctxt->error(ctxt->userData, &ctxt->lastError);
240 } else {
241 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000242 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000243 NULL, NULL, XML_FROM_XPATH,
244 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
245 extra, NULL, NULL, 0, 0,
246 "Memory allocation failed : %s\n", extra);
247 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000248 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000249 NULL, NULL, XML_FROM_XPATH,
250 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
251 NULL, NULL, NULL, 0, 0,
252 "Memory allocation failed\n");
253 }
254}
255
256/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000257 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000258 * @ctxt: an XPath parser context
259 * @extra: extra informations
260 *
261 * Handle a redefinition of attribute error
262 */
263static void
264xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
265{
266 ctxt->error = XPATH_MEMORY_ERROR;
267 if (ctxt == NULL)
268 xmlXPathErrMemory(NULL, extra);
269 else
270 xmlXPathErrMemory(ctxt->context, extra);
271}
272
273/**
274 * xmlXPathErr:
275 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000276 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000277 *
278 * Handle a Relax NG Parsing error
279 */
280void
281xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
282{
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000283 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000284 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000285 NULL, NULL, XML_FROM_XPATH,
286 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
287 XML_ERR_ERROR, NULL, 0,
288 NULL, NULL, NULL, 0, 0,
289 xmlXPathErrorMessages[error]);
290 return;
291 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000292 ctxt->error = error;
293 if (ctxt->context == NULL) {
294 __xmlRaiseError(NULL, NULL, NULL,
295 NULL, NULL, XML_FROM_XPATH,
296 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
297 XML_ERR_ERROR, NULL, 0,
298 (const char *) ctxt->base, NULL, NULL,
299 ctxt->cur - ctxt->base, 0,
300 xmlXPathErrorMessages[error]);
301 return;
302 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000303 ctxt->context->lastError.domain = XML_FROM_XPATH;
304 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
305 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000306 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000307 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
308 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
309 ctxt->context->lastError.node = ctxt->context->debugNode;
310 if (ctxt->context->error != NULL) {
311 ctxt->context->error(ctxt->context->userData,
312 &ctxt->context->lastError);
313 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000314 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000315 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
316 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
317 XML_ERR_ERROR, NULL, 0,
318 (const char *) ctxt->base, NULL, NULL,
319 ctxt->cur - ctxt->base, 0,
320 xmlXPathErrorMessages[error]);
321 }
322
323}
324
325/**
326 * xmlXPatherror:
327 * @ctxt: the XPath Parser context
328 * @file: the file name
329 * @line: the line number
330 * @no: the error number
331 *
332 * Formats an error message.
333 */
334void
335xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
336 int line ATTRIBUTE_UNUSED, int no) {
337 xmlXPathErr(ctxt, no);
338}
339
340
341/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000342 * *
343 * Parser Types *
344 * *
345 ************************************************************************/
346
347/*
348 * Types are private:
349 */
350
351typedef enum {
352 XPATH_OP_END=0,
353 XPATH_OP_AND,
354 XPATH_OP_OR,
355 XPATH_OP_EQUAL,
356 XPATH_OP_CMP,
357 XPATH_OP_PLUS,
358 XPATH_OP_MULT,
359 XPATH_OP_UNION,
360 XPATH_OP_ROOT,
361 XPATH_OP_NODE,
362 XPATH_OP_RESET,
363 XPATH_OP_COLLECT,
364 XPATH_OP_VALUE,
365 XPATH_OP_VARIABLE,
366 XPATH_OP_FUNCTION,
367 XPATH_OP_ARG,
368 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000369 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000370 XPATH_OP_SORT
371#ifdef LIBXML_XPTR_ENABLED
372 ,XPATH_OP_RANGETO
373#endif
374} xmlXPathOp;
375
376typedef enum {
377 AXIS_ANCESTOR = 1,
378 AXIS_ANCESTOR_OR_SELF,
379 AXIS_ATTRIBUTE,
380 AXIS_CHILD,
381 AXIS_DESCENDANT,
382 AXIS_DESCENDANT_OR_SELF,
383 AXIS_FOLLOWING,
384 AXIS_FOLLOWING_SIBLING,
385 AXIS_NAMESPACE,
386 AXIS_PARENT,
387 AXIS_PRECEDING,
388 AXIS_PRECEDING_SIBLING,
389 AXIS_SELF
390} xmlXPathAxisVal;
391
392typedef enum {
393 NODE_TEST_NONE = 0,
394 NODE_TEST_TYPE = 1,
395 NODE_TEST_PI = 2,
396 NODE_TEST_ALL = 3,
397 NODE_TEST_NS = 4,
398 NODE_TEST_NAME = 5
399} xmlXPathTestVal;
400
401typedef enum {
402 NODE_TYPE_NODE = 0,
403 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
404 NODE_TYPE_TEXT = XML_TEXT_NODE,
405 NODE_TYPE_PI = XML_PI_NODE
406} xmlXPathTypeVal;
407
408
409typedef struct _xmlXPathStepOp xmlXPathStepOp;
410typedef xmlXPathStepOp *xmlXPathStepOpPtr;
411struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000412 xmlXPathOp op; /* The identifier of the operation */
413 int ch1; /* First child */
414 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000415 int value;
416 int value2;
417 int value3;
418 void *value4;
419 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000420 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000421 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000422};
423
424struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000425 int nbStep; /* Number of steps in this expression */
426 int maxStep; /* Maximum number of steps allocated */
427 xmlXPathStepOp *steps; /* ops for computation of this expression */
428 int last; /* index of last step in expression */
429 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000430 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000431#ifdef DEBUG_EVAL_COUNTS
432 int nb;
433 xmlChar *string;
434#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000435};
436
437/************************************************************************
438 * *
439 * Parser Type functions *
440 * *
441 ************************************************************************/
442
443/**
444 * xmlXPathNewCompExpr:
445 *
446 * Create a new Xpath component
447 *
448 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
449 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000450static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000451xmlXPathNewCompExpr(void) {
452 xmlXPathCompExprPtr cur;
453
454 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
455 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000456 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000457 return(NULL);
458 }
459 memset(cur, 0, sizeof(xmlXPathCompExpr));
460 cur->maxStep = 10;
461 cur->nbStep = 0;
462 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
463 sizeof(xmlXPathStepOp));
464 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000465 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000466 xmlFree(cur);
467 return(NULL);
468 }
469 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
470 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000471#ifdef DEBUG_EVAL_COUNTS
472 cur->nb = 0;
473#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000474 return(cur);
475}
476
477/**
478 * xmlXPathFreeCompExpr:
479 * @comp: an XPATH comp
480 *
481 * Free up the memory allocated by @comp
482 */
483void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000484xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
485{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000486 xmlXPathStepOpPtr op;
487 int i;
488
489 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000490 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000491 if (comp->dict == NULL) {
492 for (i = 0; i < comp->nbStep; i++) {
493 op = &comp->steps[i];
494 if (op->value4 != NULL) {
495 if (op->op == XPATH_OP_VALUE)
496 xmlXPathFreeObject(op->value4);
497 else
498 xmlFree(op->value4);
499 }
500 if (op->value5 != NULL)
501 xmlFree(op->value5);
502 }
503 } else {
504 for (i = 0; i < comp->nbStep; i++) {
505 op = &comp->steps[i];
506 if (op->value4 != NULL) {
507 if (op->op == XPATH_OP_VALUE)
508 xmlXPathFreeObject(op->value4);
509 }
510 }
511 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000512 }
513 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000514 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000515 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000516#ifdef DEBUG_EVAL_COUNTS
517 if (comp->string != NULL) {
518 xmlFree(comp->string);
519 }
520#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000521 if (comp->expr != NULL) {
522 xmlFree(comp->expr);
523 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000524
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000525 xmlFree(comp);
526}
527
528/**
529 * xmlXPathCompExprAdd:
530 * @comp: the compiled expression
531 * @ch1: first child index
532 * @ch2: second child index
533 * @op: an op
534 * @value: the first int value
535 * @value2: the second int value
536 * @value3: the third int value
537 * @value4: the first string value
538 * @value5: the second string value
539 *
William M. Brack08171912003-12-29 02:52:11 +0000540 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000541 *
542 * Returns -1 in case of failure, the index otherwise
543 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000544static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000545xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
546 xmlXPathOp op, int value,
547 int value2, int value3, void *value4, void *value5) {
548 if (comp->nbStep >= comp->maxStep) {
549 xmlXPathStepOp *real;
550
551 comp->maxStep *= 2;
552 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
553 comp->maxStep * sizeof(xmlXPathStepOp));
554 if (real == NULL) {
555 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000556 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000557 return(-1);
558 }
559 comp->steps = real;
560 }
561 comp->last = comp->nbStep;
562 comp->steps[comp->nbStep].ch1 = ch1;
563 comp->steps[comp->nbStep].ch2 = ch2;
564 comp->steps[comp->nbStep].op = op;
565 comp->steps[comp->nbStep].value = value;
566 comp->steps[comp->nbStep].value2 = value2;
567 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000568 if ((comp->dict != NULL) &&
569 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
570 (op == XPATH_OP_COLLECT))) {
571 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000572 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000573 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000574 xmlFree(value4);
575 } else
576 comp->steps[comp->nbStep].value4 = NULL;
577 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000578 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000579 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000580 xmlFree(value5);
581 } else
582 comp->steps[comp->nbStep].value5 = NULL;
583 } else {
584 comp->steps[comp->nbStep].value4 = value4;
585 comp->steps[comp->nbStep].value5 = value5;
586 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000587 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000588 return(comp->nbStep++);
589}
590
Daniel Veillardf06307e2001-07-03 10:35:50 +0000591/**
592 * xmlXPathCompSwap:
593 * @comp: the compiled expression
594 * @op: operation index
595 *
596 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000597 */
598static void
599xmlXPathCompSwap(xmlXPathStepOpPtr op) {
600 int tmp;
601
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000602#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000603 /*
604 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000605 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000606 * application
607 */
608 if (xmlXPathDisableOptimizer)
609 return;
610#endif
611
Daniel Veillardf06307e2001-07-03 10:35:50 +0000612 tmp = op->ch1;
613 op->ch1 = op->ch2;
614 op->ch2 = tmp;
615}
616
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000617#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
618 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
619 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000620#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
621 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
622 (op), (val), (val2), (val3), (val4), (val5))
623
624#define PUSH_LEAVE_EXPR(op, val, val2) \
625xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
626
627#define PUSH_UNARY_EXPR(op, ch, val, val2) \
628xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
629
630#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000631xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
632 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000633
634/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000635 * *
636 * Debugging related functions *
637 * *
638 ************************************************************************/
639
Owen Taylor3473f882001-02-23 17:55:21 +0000640#define STRANGE \
641 xmlGenericError(xmlGenericErrorContext, \
642 "Internal error at %s:%d\n", \
643 __FILE__, __LINE__);
644
645#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000646static void
647xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000648 int i;
649 char shift[100];
650
651 for (i = 0;((i < depth) && (i < 25));i++)
652 shift[2 * i] = shift[2 * i + 1] = ' ';
653 shift[2 * i] = shift[2 * i + 1] = 0;
654 if (cur == NULL) {
655 fprintf(output, shift);
656 fprintf(output, "Node is NULL !\n");
657 return;
658
659 }
660
661 if ((cur->type == XML_DOCUMENT_NODE) ||
662 (cur->type == XML_HTML_DOCUMENT_NODE)) {
663 fprintf(output, shift);
664 fprintf(output, " /\n");
665 } else if (cur->type == XML_ATTRIBUTE_NODE)
666 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
667 else
668 xmlDebugDumpOneNode(output, cur, depth);
669}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000670static void
671xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000672 xmlNodePtr tmp;
673 int i;
674 char shift[100];
675
676 for (i = 0;((i < depth) && (i < 25));i++)
677 shift[2 * i] = shift[2 * i + 1] = ' ';
678 shift[2 * i] = shift[2 * i + 1] = 0;
679 if (cur == NULL) {
680 fprintf(output, shift);
681 fprintf(output, "Node is NULL !\n");
682 return;
683
684 }
685
686 while (cur != NULL) {
687 tmp = cur;
688 cur = cur->next;
689 xmlDebugDumpOneNode(output, tmp, depth);
690 }
691}
Owen Taylor3473f882001-02-23 17:55:21 +0000692
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000693static void
694xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000695 int i;
696 char shift[100];
697
698 for (i = 0;((i < depth) && (i < 25));i++)
699 shift[2 * i] = shift[2 * i + 1] = ' ';
700 shift[2 * i] = shift[2 * i + 1] = 0;
701
702 if (cur == NULL) {
703 fprintf(output, shift);
704 fprintf(output, "NodeSet is NULL !\n");
705 return;
706
707 }
708
Daniel Veillard911f49a2001-04-07 15:39:35 +0000709 if (cur != NULL) {
710 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
711 for (i = 0;i < cur->nodeNr;i++) {
712 fprintf(output, shift);
713 fprintf(output, "%d", i + 1);
714 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
715 }
Owen Taylor3473f882001-02-23 17:55:21 +0000716 }
717}
718
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000719static void
720xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000721 int i;
722 char shift[100];
723
724 for (i = 0;((i < depth) && (i < 25));i++)
725 shift[2 * i] = shift[2 * i + 1] = ' ';
726 shift[2 * i] = shift[2 * i + 1] = 0;
727
728 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
729 fprintf(output, shift);
730 fprintf(output, "Value Tree is NULL !\n");
731 return;
732
733 }
734
735 fprintf(output, shift);
736 fprintf(output, "%d", i + 1);
737 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
738}
Owen Taylor3473f882001-02-23 17:55:21 +0000739#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000740static void
741xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000742 int i;
743 char shift[100];
744
745 for (i = 0;((i < depth) && (i < 25));i++)
746 shift[2 * i] = shift[2 * i + 1] = ' ';
747 shift[2 * i] = shift[2 * i + 1] = 0;
748
749 if (cur == NULL) {
750 fprintf(output, shift);
751 fprintf(output, "LocationSet is NULL !\n");
752 return;
753
754 }
755
756 for (i = 0;i < cur->locNr;i++) {
757 fprintf(output, shift);
758 fprintf(output, "%d : ", i + 1);
759 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
760 }
761}
Daniel Veillard017b1082001-06-21 11:20:21 +0000762#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000763
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000764/**
765 * xmlXPathDebugDumpObject:
766 * @output: the FILE * to dump the output
767 * @cur: the object to inspect
768 * @depth: indentation level
769 *
770 * Dump the content of the object for debugging purposes
771 */
772void
773xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000774 int i;
775 char shift[100];
776
777 for (i = 0;((i < depth) && (i < 25));i++)
778 shift[2 * i] = shift[2 * i + 1] = ' ';
779 shift[2 * i] = shift[2 * i + 1] = 0;
780
781 fprintf(output, shift);
782
783 if (cur == NULL) {
784 fprintf(output, "Object is empty (NULL)\n");
785 return;
786 }
787 switch(cur->type) {
788 case XPATH_UNDEFINED:
789 fprintf(output, "Object is uninitialized\n");
790 break;
791 case XPATH_NODESET:
792 fprintf(output, "Object is a Node Set :\n");
793 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
794 break;
795 case XPATH_XSLT_TREE:
796 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000797 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000798 break;
799 case XPATH_BOOLEAN:
800 fprintf(output, "Object is a Boolean : ");
801 if (cur->boolval) fprintf(output, "true\n");
802 else fprintf(output, "false\n");
803 break;
804 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000805 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000806 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000807 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000808 break;
809 case -1:
810 fprintf(output, "Object is a number : -Infinity\n");
811 break;
812 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000813 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000814 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000815 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
816 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000817 } else {
818 fprintf(output, "Object is a number : %0g\n", cur->floatval);
819 }
820 }
Owen Taylor3473f882001-02-23 17:55:21 +0000821 break;
822 case XPATH_STRING:
823 fprintf(output, "Object is a string : ");
824 xmlDebugDumpString(output, cur->stringval);
825 fprintf(output, "\n");
826 break;
827 case XPATH_POINT:
828 fprintf(output, "Object is a point : index %d in node", cur->index);
829 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
830 fprintf(output, "\n");
831 break;
832 case XPATH_RANGE:
833 if ((cur->user2 == NULL) ||
834 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
835 fprintf(output, "Object is a collapsed range :\n");
836 fprintf(output, shift);
837 if (cur->index >= 0)
838 fprintf(output, "index %d in ", cur->index);
839 fprintf(output, "node\n");
840 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
841 depth + 1);
842 } else {
843 fprintf(output, "Object is a range :\n");
844 fprintf(output, shift);
845 fprintf(output, "From ");
846 if (cur->index >= 0)
847 fprintf(output, "index %d in ", cur->index);
848 fprintf(output, "node\n");
849 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
850 depth + 1);
851 fprintf(output, shift);
852 fprintf(output, "To ");
853 if (cur->index2 >= 0)
854 fprintf(output, "index %d in ", cur->index2);
855 fprintf(output, "node\n");
856 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
857 depth + 1);
858 fprintf(output, "\n");
859 }
860 break;
861 case XPATH_LOCATIONSET:
862#if defined(LIBXML_XPTR_ENABLED)
863 fprintf(output, "Object is a Location Set:\n");
864 xmlXPathDebugDumpLocationSet(output,
865 (xmlLocationSetPtr) cur->user, depth);
866#endif
867 break;
868 case XPATH_USERS:
869 fprintf(output, "Object is user defined\n");
870 break;
871 }
872}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000873
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000874static void
875xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000876 xmlXPathStepOpPtr op, int depth) {
877 int i;
878 char shift[100];
879
880 for (i = 0;((i < depth) && (i < 25));i++)
881 shift[2 * i] = shift[2 * i + 1] = ' ';
882 shift[2 * i] = shift[2 * i + 1] = 0;
883
884 fprintf(output, shift);
885 if (op == NULL) {
886 fprintf(output, "Step is NULL\n");
887 return;
888 }
889 switch (op->op) {
890 case XPATH_OP_END:
891 fprintf(output, "END"); break;
892 case XPATH_OP_AND:
893 fprintf(output, "AND"); break;
894 case XPATH_OP_OR:
895 fprintf(output, "OR"); break;
896 case XPATH_OP_EQUAL:
897 if (op->value)
898 fprintf(output, "EQUAL =");
899 else
900 fprintf(output, "EQUAL !=");
901 break;
902 case XPATH_OP_CMP:
903 if (op->value)
904 fprintf(output, "CMP <");
905 else
906 fprintf(output, "CMP >");
907 if (!op->value2)
908 fprintf(output, "=");
909 break;
910 case XPATH_OP_PLUS:
911 if (op->value == 0)
912 fprintf(output, "PLUS -");
913 else if (op->value == 1)
914 fprintf(output, "PLUS +");
915 else if (op->value == 2)
916 fprintf(output, "PLUS unary -");
917 else if (op->value == 3)
918 fprintf(output, "PLUS unary - -");
919 break;
920 case XPATH_OP_MULT:
921 if (op->value == 0)
922 fprintf(output, "MULT *");
923 else if (op->value == 1)
924 fprintf(output, "MULT div");
925 else
926 fprintf(output, "MULT mod");
927 break;
928 case XPATH_OP_UNION:
929 fprintf(output, "UNION"); break;
930 case XPATH_OP_ROOT:
931 fprintf(output, "ROOT"); break;
932 case XPATH_OP_NODE:
933 fprintf(output, "NODE"); break;
934 case XPATH_OP_RESET:
935 fprintf(output, "RESET"); break;
936 case XPATH_OP_SORT:
937 fprintf(output, "SORT"); break;
938 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000939 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
940 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
941 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000942 const xmlChar *prefix = op->value4;
943 const xmlChar *name = op->value5;
944
945 fprintf(output, "COLLECT ");
946 switch (axis) {
947 case AXIS_ANCESTOR:
948 fprintf(output, " 'ancestors' "); break;
949 case AXIS_ANCESTOR_OR_SELF:
950 fprintf(output, " 'ancestors-or-self' "); break;
951 case AXIS_ATTRIBUTE:
952 fprintf(output, " 'attributes' "); break;
953 case AXIS_CHILD:
954 fprintf(output, " 'child' "); break;
955 case AXIS_DESCENDANT:
956 fprintf(output, " 'descendant' "); break;
957 case AXIS_DESCENDANT_OR_SELF:
958 fprintf(output, " 'descendant-or-self' "); break;
959 case AXIS_FOLLOWING:
960 fprintf(output, " 'following' "); break;
961 case AXIS_FOLLOWING_SIBLING:
962 fprintf(output, " 'following-siblings' "); break;
963 case AXIS_NAMESPACE:
964 fprintf(output, " 'namespace' "); break;
965 case AXIS_PARENT:
966 fprintf(output, " 'parent' "); break;
967 case AXIS_PRECEDING:
968 fprintf(output, " 'preceding' "); break;
969 case AXIS_PRECEDING_SIBLING:
970 fprintf(output, " 'preceding-sibling' "); break;
971 case AXIS_SELF:
972 fprintf(output, " 'self' "); break;
973 }
974 switch (test) {
975 case NODE_TEST_NONE:
976 fprintf(output, "'none' "); break;
977 case NODE_TEST_TYPE:
978 fprintf(output, "'type' "); break;
979 case NODE_TEST_PI:
980 fprintf(output, "'PI' "); break;
981 case NODE_TEST_ALL:
982 fprintf(output, "'all' "); break;
983 case NODE_TEST_NS:
984 fprintf(output, "'namespace' "); break;
985 case NODE_TEST_NAME:
986 fprintf(output, "'name' "); break;
987 }
988 switch (type) {
989 case NODE_TYPE_NODE:
990 fprintf(output, "'node' "); break;
991 case NODE_TYPE_COMMENT:
992 fprintf(output, "'comment' "); break;
993 case NODE_TYPE_TEXT:
994 fprintf(output, "'text' "); break;
995 case NODE_TYPE_PI:
996 fprintf(output, "'PI' "); break;
997 }
998 if (prefix != NULL)
999 fprintf(output, "%s:", prefix);
1000 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001001 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001002 break;
1003
1004 }
1005 case XPATH_OP_VALUE: {
1006 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1007
1008 fprintf(output, "ELEM ");
1009 xmlXPathDebugDumpObject(output, object, 0);
1010 goto finish;
1011 }
1012 case XPATH_OP_VARIABLE: {
1013 const xmlChar *prefix = op->value5;
1014 const xmlChar *name = op->value4;
1015
1016 if (prefix != NULL)
1017 fprintf(output, "VARIABLE %s:%s", prefix, name);
1018 else
1019 fprintf(output, "VARIABLE %s", name);
1020 break;
1021 }
1022 case XPATH_OP_FUNCTION: {
1023 int nbargs = op->value;
1024 const xmlChar *prefix = op->value5;
1025 const xmlChar *name = op->value4;
1026
1027 if (prefix != NULL)
1028 fprintf(output, "FUNCTION %s:%s(%d args)",
1029 prefix, name, nbargs);
1030 else
1031 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1032 break;
1033 }
1034 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1035 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001036 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001037#ifdef LIBXML_XPTR_ENABLED
1038 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1039#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001040 default:
1041 fprintf(output, "UNKNOWN %d\n", op->op); return;
1042 }
1043 fprintf(output, "\n");
1044finish:
1045 if (op->ch1 >= 0)
1046 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1047 if (op->ch2 >= 0)
1048 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1049}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001050
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001051/**
1052 * xmlXPathDebugDumpCompExpr:
1053 * @output: the FILE * for the output
1054 * @comp: the precompiled XPath expression
1055 * @depth: the indentation level.
1056 *
1057 * Dumps the tree of the compiled XPath expression.
1058 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001059void
1060xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1061 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001062 int i;
1063 char shift[100];
1064
1065 for (i = 0;((i < depth) && (i < 25));i++)
1066 shift[2 * i] = shift[2 * i + 1] = ' ';
1067 shift[2 * i] = shift[2 * i + 1] = 0;
1068
1069 fprintf(output, shift);
1070
1071 if (comp == NULL) {
1072 fprintf(output, "Compiled Expression is NULL\n");
1073 return;
1074 }
1075 fprintf(output, "Compiled Expression : %d elements\n",
1076 comp->nbStep);
1077 i = comp->last;
1078 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1079}
Daniel Veillard017b1082001-06-21 11:20:21 +00001080#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001081
1082/************************************************************************
1083 * *
1084 * Parser stacks related functions and macros *
1085 * *
1086 ************************************************************************/
1087
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001088/**
1089 * valuePop:
1090 * @ctxt: an XPath evaluation context
1091 *
1092 * Pops the top XPath object from the value stack
1093 *
1094 * Returns the XPath object just removed
1095 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001096extern xmlXPathObjectPtr
1097valuePop(xmlXPathParserContextPtr ctxt)
1098{
1099 xmlXPathObjectPtr ret;
1100
1101 if (ctxt->valueNr <= 0)
1102 return (0);
1103 ctxt->valueNr--;
1104 if (ctxt->valueNr > 0)
1105 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1106 else
1107 ctxt->value = NULL;
1108 ret = ctxt->valueTab[ctxt->valueNr];
1109 ctxt->valueTab[ctxt->valueNr] = 0;
1110 return (ret);
1111}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001112/**
1113 * valuePush:
1114 * @ctxt: an XPath evaluation context
1115 * @value: the XPath object
1116 *
1117 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001118 *
1119 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001120 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001121extern int
1122valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1123{
1124 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001125 xmlXPathObjectPtr *tmp;
1126
1127 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1128 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00001129 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001130 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00001131 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1132 return (0);
1133 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001134 ctxt->valueMax *= 2;
1135 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00001136 }
1137 ctxt->valueTab[ctxt->valueNr] = value;
1138 ctxt->value = value;
1139 return (ctxt->valueNr++);
1140}
Owen Taylor3473f882001-02-23 17:55:21 +00001141
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001142/**
1143 * xmlXPathPopBoolean:
1144 * @ctxt: an XPath parser context
1145 *
1146 * Pops a boolean from the stack, handling conversion if needed.
1147 * Check error with #xmlXPathCheckError.
1148 *
1149 * Returns the boolean
1150 */
1151int
1152xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1153 xmlXPathObjectPtr obj;
1154 int ret;
1155
1156 obj = valuePop(ctxt);
1157 if (obj == NULL) {
1158 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1159 return(0);
1160 }
William M. Brack08171912003-12-29 02:52:11 +00001161 if (obj->type != XPATH_BOOLEAN)
1162 ret = xmlXPathCastToBoolean(obj);
1163 else
1164 ret = obj->boolval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001165 xmlXPathFreeObject(obj);
1166 return(ret);
1167}
1168
1169/**
1170 * xmlXPathPopNumber:
1171 * @ctxt: an XPath parser context
1172 *
1173 * Pops a number from the stack, handling conversion if needed.
1174 * Check error with #xmlXPathCheckError.
1175 *
1176 * Returns the number
1177 */
1178double
1179xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1180 xmlXPathObjectPtr obj;
1181 double ret;
1182
1183 obj = valuePop(ctxt);
1184 if (obj == NULL) {
1185 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1186 return(0);
1187 }
William M. Brack08171912003-12-29 02:52:11 +00001188 if (obj->type != XPATH_NUMBER)
1189 ret = xmlXPathCastToNumber(obj);
1190 else
1191 ret = obj->floatval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001192 xmlXPathFreeObject(obj);
1193 return(ret);
1194}
1195
1196/**
1197 * xmlXPathPopString:
1198 * @ctxt: an XPath parser context
1199 *
1200 * Pops a string from the stack, handling conversion if needed.
1201 * Check error with #xmlXPathCheckError.
1202 *
1203 * Returns the string
1204 */
1205xmlChar *
1206xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1207 xmlXPathObjectPtr obj;
1208 xmlChar * ret;
1209
1210 obj = valuePop(ctxt);
1211 if (obj == NULL) {
1212 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1213 return(NULL);
1214 }
William M. Brack08171912003-12-29 02:52:11 +00001215 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001216 /* TODO: needs refactoring somewhere else */
1217 if (obj->stringval == ret)
1218 obj->stringval = NULL;
1219 xmlXPathFreeObject(obj);
1220 return(ret);
1221}
1222
1223/**
1224 * xmlXPathPopNodeSet:
1225 * @ctxt: an XPath parser context
1226 *
1227 * Pops a node-set from the stack, handling conversion if needed.
1228 * Check error with #xmlXPathCheckError.
1229 *
1230 * Returns the node-set
1231 */
1232xmlNodeSetPtr
1233xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1234 xmlXPathObjectPtr obj;
1235 xmlNodeSetPtr ret;
1236
1237 if (ctxt->value == NULL) {
1238 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1239 return(NULL);
1240 }
1241 if (!xmlXPathStackIsNodeSet(ctxt)) {
1242 xmlXPathSetTypeError(ctxt);
1243 return(NULL);
1244 }
1245 obj = valuePop(ctxt);
1246 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00001247#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00001248 /* to fix memory leak of not clearing obj->user */
1249 if (obj->boolval && obj->user != NULL)
1250 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00001251#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001252 xmlXPathFreeNodeSetList(obj);
1253 return(ret);
1254}
1255
1256/**
1257 * xmlXPathPopExternal:
1258 * @ctxt: an XPath parser context
1259 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001260 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001261 * Check error with #xmlXPathCheckError.
1262 *
1263 * Returns the object
1264 */
1265void *
1266xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1267 xmlXPathObjectPtr obj;
1268 void * ret;
1269
1270 if (ctxt->value == NULL) {
1271 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1272 return(NULL);
1273 }
1274 if (ctxt->value->type != XPATH_USERS) {
1275 xmlXPathSetTypeError(ctxt);
1276 return(NULL);
1277 }
1278 obj = valuePop(ctxt);
1279 ret = obj->user;
1280 xmlXPathFreeObject(obj);
1281 return(ret);
1282}
1283
Owen Taylor3473f882001-02-23 17:55:21 +00001284/*
1285 * Macros for accessing the content. Those should be used only by the parser,
1286 * and not exported.
1287 *
1288 * Dirty macros, i.e. one need to make assumption on the context to use them
1289 *
1290 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1291 * CUR returns the current xmlChar value, i.e. a 8 bit value
1292 * in ISO-Latin or UTF-8.
1293 * This should be used internally by the parser
1294 * only to compare to ASCII values otherwise it would break when
1295 * running with UTF-8 encoding.
1296 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1297 * to compare on ASCII based substring.
1298 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1299 * strings within the parser.
1300 * CURRENT Returns the current char value, with the full decoding of
1301 * UTF-8 if we are using this mode. It returns an int.
1302 * NEXT Skip to the next character, this does the proper decoding
1303 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1304 * It returns the pointer to the current xmlChar.
1305 */
1306
1307#define CUR (*ctxt->cur)
1308#define SKIP(val) ctxt->cur += (val)
1309#define NXT(val) ctxt->cur[(val)]
1310#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001311#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1312
1313#define COPY_BUF(l,b,i,v) \
1314 if (l == 1) b[i++] = (xmlChar) v; \
1315 else i += xmlCopyChar(l,&b[i],v)
1316
1317#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001318
1319#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001320 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001321
1322#define CURRENT (*ctxt->cur)
1323#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1324
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001325
1326#ifndef DBL_DIG
1327#define DBL_DIG 16
1328#endif
1329#ifndef DBL_EPSILON
1330#define DBL_EPSILON 1E-9
1331#endif
1332
1333#define UPPER_DOUBLE 1E9
1334#define LOWER_DOUBLE 1E-5
1335
1336#define INTEGER_DIGITS DBL_DIG
1337#define FRACTION_DIGITS (DBL_DIG + 1)
1338#define EXPONENT_DIGITS (3 + 2)
1339
1340/**
1341 * xmlXPathFormatNumber:
1342 * @number: number to format
1343 * @buffer: output buffer
1344 * @buffersize: size of output buffer
1345 *
1346 * Convert the number into a string representation.
1347 */
1348static void
1349xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1350{
Daniel Veillardcda96922001-08-21 10:56:31 +00001351 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001352 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001353 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001354 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001355 break;
1356 case -1:
1357 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001358 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001359 break;
1360 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001361 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001362 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001363 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001364 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001365 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001366 } else if (number == ((int) number)) {
1367 char work[30];
1368 char *ptr, *cur;
1369 int res, value = (int) number;
1370
1371 ptr = &buffer[0];
1372 if (value < 0) {
1373 *ptr++ = '-';
1374 value = -value;
1375 }
1376 if (value == 0) {
1377 *ptr++ = '0';
1378 } else {
1379 cur = &work[0];
1380 while (value != 0) {
1381 res = value % 10;
1382 value = value / 10;
1383 *cur++ = '0' + res;
1384 }
1385 cur--;
1386 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1387 *ptr++ = *cur--;
1388 }
1389 }
1390 if (ptr - buffer < buffersize) {
1391 *ptr = 0;
1392 } else if (buffersize > 0) {
1393 ptr--;
1394 *ptr = 0;
1395 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001396 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001397 /* 3 is sign, decimal point, and terminating zero */
1398 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1399 int integer_place, fraction_place;
1400 char *ptr;
1401 char *after_fraction;
1402 double absolute_value;
1403 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001404
Bjorn Reese70a9da52001-04-21 16:57:29 +00001405 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001406
Bjorn Reese70a9da52001-04-21 16:57:29 +00001407 /*
1408 * First choose format - scientific or regular floating point.
1409 * In either case, result is in work, and after_fraction points
1410 * just past the fractional part.
1411 */
1412 if ( ((absolute_value > UPPER_DOUBLE) ||
1413 (absolute_value < LOWER_DOUBLE)) &&
1414 (absolute_value != 0.0) ) {
1415 /* Use scientific notation */
1416 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1417 fraction_place = DBL_DIG - 1;
1418 snprintf(work, sizeof(work),"%*.*e",
1419 integer_place, fraction_place, number);
1420 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001421 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001422 else {
1423 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001424 if (absolute_value > 0.0)
1425 integer_place = 1 + (int)log10(absolute_value);
1426 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001427 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001428 fraction_place = (integer_place > 0)
1429 ? DBL_DIG - integer_place
1430 : DBL_DIG;
1431 size = snprintf(work, sizeof(work), "%0.*f",
1432 fraction_place, number);
1433 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001434 }
1435
Bjorn Reese70a9da52001-04-21 16:57:29 +00001436 /* Remove fractional trailing zeroes */
1437 ptr = after_fraction;
1438 while (*(--ptr) == '0')
1439 ;
1440 if (*ptr != '.')
1441 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001442 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001443
1444 /* Finally copy result back to caller */
1445 size = strlen(work) + 1;
1446 if (size > buffersize) {
1447 work[buffersize - 1] = 0;
1448 size = buffersize;
1449 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001450 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001451 }
1452 break;
1453 }
1454}
1455
Owen Taylor3473f882001-02-23 17:55:21 +00001456
1457/************************************************************************
1458 * *
1459 * Routines to handle NodeSets *
1460 * *
1461 ************************************************************************/
1462
1463/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001464 * xmlXPathOrderDocElems:
1465 * @doc: an input document
1466 *
1467 * Call this routine to speed up XPath computation on static documents.
1468 * This stamps all the element nodes with the document order
1469 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00001470 * field, the value stored is actually - the node number (starting at -1)
1471 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001472 *
William M. Brack08171912003-12-29 02:52:11 +00001473 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001474 * of error.
1475 */
1476long
1477xmlXPathOrderDocElems(xmlDocPtr doc) {
1478 long count = 0;
1479 xmlNodePtr cur;
1480
1481 if (doc == NULL)
1482 return(-1);
1483 cur = doc->children;
1484 while (cur != NULL) {
1485 if (cur->type == XML_ELEMENT_NODE) {
1486 cur->content = (void *) (-(++count));
1487 if (cur->children != NULL) {
1488 cur = cur->children;
1489 continue;
1490 }
1491 }
1492 if (cur->next != NULL) {
1493 cur = cur->next;
1494 continue;
1495 }
1496 do {
1497 cur = cur->parent;
1498 if (cur == NULL)
1499 break;
1500 if (cur == (xmlNodePtr) doc) {
1501 cur = NULL;
1502 break;
1503 }
1504 if (cur->next != NULL) {
1505 cur = cur->next;
1506 break;
1507 }
1508 } while (cur != NULL);
1509 }
1510 return(count);
1511}
1512
1513/**
Owen Taylor3473f882001-02-23 17:55:21 +00001514 * xmlXPathCmpNodes:
1515 * @node1: the first node
1516 * @node2: the second node
1517 *
1518 * Compare two nodes w.r.t document order
1519 *
1520 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00001521 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001522 */
1523int
1524xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1525 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001526 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001527 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001528 xmlNodePtr cur, root;
1529
1530 if ((node1 == NULL) || (node2 == NULL))
1531 return(-2);
1532 /*
1533 * a couple of optimizations which will avoid computations in most cases
1534 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001535 if (node1->type == XML_ATTRIBUTE_NODE) {
1536 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001537 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001538 node1 = node1->parent;
1539 }
1540 if (node2->type == XML_ATTRIBUTE_NODE) {
1541 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001542 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001543 node2 = node2->parent;
1544 }
1545 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001546 if (attr1 == attr2) {
1547 /* not required, but we keep attributes in order */
1548 if (attr1 != 0) {
1549 cur = attrNode2->prev;
1550 while (cur != NULL) {
1551 if (cur == attrNode1)
1552 return (1);
1553 cur = cur->prev;
1554 }
1555 return (-1);
1556 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001557 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001558 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001559 if (attr2 == 1)
1560 return(1);
1561 return(-1);
1562 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001563 if ((node1->type == XML_NAMESPACE_DECL) ||
1564 (node2->type == XML_NAMESPACE_DECL))
1565 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001566 if (node1 == node2->prev)
1567 return(1);
1568 if (node1 == node2->next)
1569 return(-1);
1570
1571 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001572 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001573 */
1574 if ((node1->type == XML_ELEMENT_NODE) &&
1575 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001576 (0 > (long) node1->content) &&
1577 (0 > (long) node2->content) &&
1578 (node1->doc == node2->doc)) {
1579 long l1, l2;
1580
1581 l1 = -((long) node1->content);
1582 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001583 if (l1 < l2)
1584 return(1);
1585 if (l1 > l2)
1586 return(-1);
1587 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001588
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001589 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001590 * compute depth to root
1591 */
1592 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1593 if (cur == node1)
1594 return(1);
1595 depth2++;
1596 }
1597 root = cur;
1598 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1599 if (cur == node2)
1600 return(-1);
1601 depth1++;
1602 }
1603 /*
1604 * Distinct document (or distinct entities :-( ) case.
1605 */
1606 if (root != cur) {
1607 return(-2);
1608 }
1609 /*
1610 * get the nearest common ancestor.
1611 */
1612 while (depth1 > depth2) {
1613 depth1--;
1614 node1 = node1->parent;
1615 }
1616 while (depth2 > depth1) {
1617 depth2--;
1618 node2 = node2->parent;
1619 }
1620 while (node1->parent != node2->parent) {
1621 node1 = node1->parent;
1622 node2 = node2->parent;
1623 /* should not happen but just in case ... */
1624 if ((node1 == NULL) || (node2 == NULL))
1625 return(-2);
1626 }
1627 /*
1628 * Find who's first.
1629 */
Daniel Veillardf49be472004-02-17 11:48:18 +00001630 if (node1 == node2->prev)
1631 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001632 if (node1 == node2->next)
1633 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00001634 /*
1635 * Speedup using document order if availble.
1636 */
1637 if ((node1->type == XML_ELEMENT_NODE) &&
1638 (node2->type == XML_ELEMENT_NODE) &&
1639 (0 > (long) node1->content) &&
1640 (0 > (long) node2->content) &&
1641 (node1->doc == node2->doc)) {
1642 long l1, l2;
1643
1644 l1 = -((long) node1->content);
1645 l2 = -((long) node2->content);
1646 if (l1 < l2)
1647 return(1);
1648 if (l1 > l2)
1649 return(-1);
1650 }
1651
Owen Taylor3473f882001-02-23 17:55:21 +00001652 for (cur = node1->next;cur != NULL;cur = cur->next)
1653 if (cur == node2)
1654 return(1);
1655 return(-1); /* assume there is no sibling list corruption */
1656}
1657
1658/**
1659 * xmlXPathNodeSetSort:
1660 * @set: the node set
1661 *
1662 * Sort the node set in document order
1663 */
1664void
1665xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001666 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001667 xmlNodePtr tmp;
1668
1669 if (set == NULL)
1670 return;
1671
1672 /* Use Shell's sort to sort the node-set */
1673 len = set->nodeNr;
1674 for (incr = len / 2; incr > 0; incr /= 2) {
1675 for (i = incr; i < len; i++) {
1676 j = i - incr;
1677 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001678 if (xmlXPathCmpNodes(set->nodeTab[j],
1679 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001680 tmp = set->nodeTab[j];
1681 set->nodeTab[j] = set->nodeTab[j + incr];
1682 set->nodeTab[j + incr] = tmp;
1683 j -= incr;
1684 } else
1685 break;
1686 }
1687 }
1688 }
1689}
1690
1691#define XML_NODESET_DEFAULT 10
1692/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001693 * xmlXPathNodeSetDupNs:
1694 * @node: the parent node of the namespace XPath node
1695 * @ns: the libxml namespace declaration node.
1696 *
1697 * Namespace node in libxml don't match the XPath semantic. In a node set
1698 * the namespace nodes are duplicated and the next pointer is set to the
1699 * parent node in the XPath semantic.
1700 *
1701 * Returns the newly created object.
1702 */
1703static xmlNodePtr
1704xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1705 xmlNsPtr cur;
1706
1707 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1708 return(NULL);
1709 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1710 return((xmlNodePtr) ns);
1711
1712 /*
1713 * Allocate a new Namespace and fill the fields.
1714 */
1715 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1716 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001717 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001718 return(NULL);
1719 }
1720 memset(cur, 0, sizeof(xmlNs));
1721 cur->type = XML_NAMESPACE_DECL;
1722 if (ns->href != NULL)
1723 cur->href = xmlStrdup(ns->href);
1724 if (ns->prefix != NULL)
1725 cur->prefix = xmlStrdup(ns->prefix);
1726 cur->next = (xmlNsPtr) node;
1727 return((xmlNodePtr) cur);
1728}
1729
1730/**
1731 * xmlXPathNodeSetFreeNs:
1732 * @ns: the XPath namespace node found in a nodeset.
1733 *
William M. Brack08171912003-12-29 02:52:11 +00001734 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001735 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00001736 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001737 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001738void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001739xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1740 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1741 return;
1742
1743 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1744 if (ns->href != NULL)
1745 xmlFree((xmlChar *)ns->href);
1746 if (ns->prefix != NULL)
1747 xmlFree((xmlChar *)ns->prefix);
1748 xmlFree(ns);
1749 }
1750}
1751
1752/**
Owen Taylor3473f882001-02-23 17:55:21 +00001753 * xmlXPathNodeSetCreate:
1754 * @val: an initial xmlNodePtr, or NULL
1755 *
1756 * Create a new xmlNodeSetPtr of type double and of value @val
1757 *
1758 * Returns the newly created object.
1759 */
1760xmlNodeSetPtr
1761xmlXPathNodeSetCreate(xmlNodePtr val) {
1762 xmlNodeSetPtr ret;
1763
1764 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1765 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001766 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001767 return(NULL);
1768 }
1769 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1770 if (val != NULL) {
1771 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1772 sizeof(xmlNodePtr));
1773 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001774 xmlXPathErrMemory(NULL, "creating nodeset\n");
1775 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001776 return(NULL);
1777 }
1778 memset(ret->nodeTab, 0 ,
1779 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1780 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001781 if (val->type == XML_NAMESPACE_DECL) {
1782 xmlNsPtr ns = (xmlNsPtr) val;
1783
1784 ret->nodeTab[ret->nodeNr++] =
1785 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1786 } else
1787 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001788 }
1789 return(ret);
1790}
1791
1792/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001793 * xmlXPathNodeSetContains:
1794 * @cur: the node-set
1795 * @val: the node
1796 *
1797 * checks whether @cur contains @val
1798 *
1799 * Returns true (1) if @cur contains @val, false (0) otherwise
1800 */
1801int
1802xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1803 int i;
1804
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001805 if (val->type == XML_NAMESPACE_DECL) {
1806 for (i = 0; i < cur->nodeNr; i++) {
1807 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1808 xmlNsPtr ns1, ns2;
1809
1810 ns1 = (xmlNsPtr) val;
1811 ns2 = (xmlNsPtr) cur->nodeTab[i];
1812 if (ns1 == ns2)
1813 return(1);
1814 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1815 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1816 return(1);
1817 }
1818 }
1819 } else {
1820 for (i = 0; i < cur->nodeNr; i++) {
1821 if (cur->nodeTab[i] == val)
1822 return(1);
1823 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001824 }
1825 return(0);
1826}
1827
1828/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001829 * xmlXPathNodeSetAddNs:
1830 * @cur: the initial node set
1831 * @node: the hosting node
1832 * @ns: a the namespace node
1833 *
1834 * add a new namespace node to an existing NodeSet
1835 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001836void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001837xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1838 int i;
1839
1840 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1841 (node->type != XML_ELEMENT_NODE))
1842 return;
1843
William M. Brack08171912003-12-29 02:52:11 +00001844 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001845 /*
William M. Brack08171912003-12-29 02:52:11 +00001846 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001847 */
1848 for (i = 0;i < cur->nodeNr;i++) {
1849 if ((cur->nodeTab[i] != NULL) &&
1850 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001851 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001852 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1853 return;
1854 }
1855
1856 /*
1857 * grow the nodeTab if needed
1858 */
1859 if (cur->nodeMax == 0) {
1860 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1861 sizeof(xmlNodePtr));
1862 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001863 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001864 return;
1865 }
1866 memset(cur->nodeTab, 0 ,
1867 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1868 cur->nodeMax = XML_NODESET_DEFAULT;
1869 } else if (cur->nodeNr == cur->nodeMax) {
1870 xmlNodePtr *temp;
1871
1872 cur->nodeMax *= 2;
1873 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1874 sizeof(xmlNodePtr));
1875 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001876 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001877 return;
1878 }
1879 cur->nodeTab = temp;
1880 }
1881 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1882}
1883
1884/**
Owen Taylor3473f882001-02-23 17:55:21 +00001885 * xmlXPathNodeSetAdd:
1886 * @cur: the initial node set
1887 * @val: a new xmlNodePtr
1888 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001889 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001890 */
1891void
1892xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1893 int i;
1894
1895 if (val == NULL) return;
1896
Daniel Veillardef0b4502003-03-24 13:57:34 +00001897#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001898 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1899 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001900#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001901
William M. Brack08171912003-12-29 02:52:11 +00001902 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001903 /*
William M. Brack08171912003-12-29 02:52:11 +00001904 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00001905 */
1906 for (i = 0;i < cur->nodeNr;i++)
1907 if (cur->nodeTab[i] == val) return;
1908
1909 /*
1910 * grow the nodeTab if needed
1911 */
1912 if (cur->nodeMax == 0) {
1913 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1914 sizeof(xmlNodePtr));
1915 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001916 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001917 return;
1918 }
1919 memset(cur->nodeTab, 0 ,
1920 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1921 cur->nodeMax = XML_NODESET_DEFAULT;
1922 } else if (cur->nodeNr == cur->nodeMax) {
1923 xmlNodePtr *temp;
1924
1925 cur->nodeMax *= 2;
1926 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1927 sizeof(xmlNodePtr));
1928 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001929 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001930 return;
1931 }
1932 cur->nodeTab = temp;
1933 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001934 if (val->type == XML_NAMESPACE_DECL) {
1935 xmlNsPtr ns = (xmlNsPtr) val;
1936
1937 cur->nodeTab[cur->nodeNr++] =
1938 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1939 } else
1940 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001941}
1942
1943/**
1944 * xmlXPathNodeSetAddUnique:
1945 * @cur: the initial node set
1946 * @val: a new xmlNodePtr
1947 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001948 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001949 * when we are sure the node is not already in the set.
1950 */
1951void
1952xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1953 if (val == NULL) return;
1954
Daniel Veillardef0b4502003-03-24 13:57:34 +00001955#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001956 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1957 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001958#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001959
William M. Brack08171912003-12-29 02:52:11 +00001960 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001961 /*
1962 * grow the nodeTab if needed
1963 */
1964 if (cur->nodeMax == 0) {
1965 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1966 sizeof(xmlNodePtr));
1967 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001968 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001969 return;
1970 }
1971 memset(cur->nodeTab, 0 ,
1972 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1973 cur->nodeMax = XML_NODESET_DEFAULT;
1974 } else if (cur->nodeNr == cur->nodeMax) {
1975 xmlNodePtr *temp;
1976
1977 cur->nodeMax *= 2;
1978 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1979 sizeof(xmlNodePtr));
1980 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001981 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001982 return;
1983 }
1984 cur->nodeTab = temp;
1985 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001986 if (val->type == XML_NAMESPACE_DECL) {
1987 xmlNsPtr ns = (xmlNsPtr) val;
1988
1989 cur->nodeTab[cur->nodeNr++] =
1990 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1991 } else
1992 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001993}
1994
1995/**
1996 * xmlXPathNodeSetMerge:
1997 * @val1: the first NodeSet or NULL
1998 * @val2: the second NodeSet
1999 *
2000 * Merges two nodesets, all nodes from @val2 are added to @val1
2001 * if @val1 is NULL, a new set is created and copied from @val2
2002 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002003 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002004 */
2005xmlNodeSetPtr
2006xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002007 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00002008
2009 if (val2 == NULL) return(val1);
2010 if (val1 == NULL) {
2011 val1 = xmlXPathNodeSetCreate(NULL);
2012 }
2013
William M. Brack08171912003-12-29 02:52:11 +00002014 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002015 initNr = val1->nodeNr;
2016
2017 for (i = 0;i < val2->nodeNr;i++) {
2018 /*
William M. Brack08171912003-12-29 02:52:11 +00002019 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00002020 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002021 skip = 0;
2022 for (j = 0; j < initNr; j++) {
2023 if (val1->nodeTab[j] == val2->nodeTab[i]) {
2024 skip = 1;
2025 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002026 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
2027 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
2028 xmlNsPtr ns1, ns2;
2029 ns1 = (xmlNsPtr) val1->nodeTab[j];
2030 ns2 = (xmlNsPtr) val2->nodeTab[i];
2031 if ((ns1->next == ns2->next) &&
2032 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
2033 skip = 1;
2034 break;
2035 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002036 }
2037 }
2038 if (skip)
2039 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00002040
2041 /*
2042 * grow the nodeTab if needed
2043 */
2044 if (val1->nodeMax == 0) {
2045 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2046 sizeof(xmlNodePtr));
2047 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002048 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002049 return(NULL);
2050 }
2051 memset(val1->nodeTab, 0 ,
2052 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2053 val1->nodeMax = XML_NODESET_DEFAULT;
2054 } else if (val1->nodeNr == val1->nodeMax) {
2055 xmlNodePtr *temp;
2056
2057 val1->nodeMax *= 2;
2058 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2059 sizeof(xmlNodePtr));
2060 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002061 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002062 return(NULL);
2063 }
2064 val1->nodeTab = temp;
2065 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002066 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2067 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2068
2069 val1->nodeTab[val1->nodeNr++] =
2070 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2071 } else
2072 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002073 }
2074
2075 return(val1);
2076}
2077
2078/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002079 * xmlXPathNodeSetMergeUnique:
2080 * @val1: the first NodeSet or NULL
2081 * @val2: the second NodeSet
2082 *
2083 * Merges two nodesets, all nodes from @val2 are added to @val1
2084 * if @val1 is NULL, a new set is created and copied from @val2
2085 *
2086 * Returns @val1 once extended or NULL in case of error.
2087 */
2088static xmlNodeSetPtr
2089xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002090 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002091
2092 if (val2 == NULL) return(val1);
2093 if (val1 == NULL) {
2094 val1 = xmlXPathNodeSetCreate(NULL);
2095 }
2096
William M. Brack08171912003-12-29 02:52:11 +00002097 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002098
2099 for (i = 0;i < val2->nodeNr;i++) {
2100 /*
2101 * grow the nodeTab if needed
2102 */
2103 if (val1->nodeMax == 0) {
2104 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2105 sizeof(xmlNodePtr));
2106 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002107 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002108 return(NULL);
2109 }
2110 memset(val1->nodeTab, 0 ,
2111 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2112 val1->nodeMax = XML_NODESET_DEFAULT;
2113 } else if (val1->nodeNr == val1->nodeMax) {
2114 xmlNodePtr *temp;
2115
2116 val1->nodeMax *= 2;
2117 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2118 sizeof(xmlNodePtr));
2119 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002120 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002121 return(NULL);
2122 }
2123 val1->nodeTab = temp;
2124 }
2125 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2126 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2127
2128 val1->nodeTab[val1->nodeNr++] =
2129 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2130 } else
2131 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2132 }
2133
2134 return(val1);
2135}
2136
2137/**
Owen Taylor3473f882001-02-23 17:55:21 +00002138 * xmlXPathNodeSetDel:
2139 * @cur: the initial node set
2140 * @val: an xmlNodePtr
2141 *
2142 * Removes an xmlNodePtr from an existing NodeSet
2143 */
2144void
2145xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2146 int i;
2147
2148 if (cur == NULL) return;
2149 if (val == NULL) return;
2150
2151 /*
William M. Brack08171912003-12-29 02:52:11 +00002152 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002153 */
2154 for (i = 0;i < cur->nodeNr;i++)
2155 if (cur->nodeTab[i] == val) break;
2156
William M. Brack08171912003-12-29 02:52:11 +00002157 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002158#ifdef DEBUG
2159 xmlGenericError(xmlGenericErrorContext,
2160 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2161 val->name);
2162#endif
2163 return;
2164 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002165 if ((cur->nodeTab[i] != NULL) &&
2166 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2167 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002168 cur->nodeNr--;
2169 for (;i < cur->nodeNr;i++)
2170 cur->nodeTab[i] = cur->nodeTab[i + 1];
2171 cur->nodeTab[cur->nodeNr] = NULL;
2172}
2173
2174/**
2175 * xmlXPathNodeSetRemove:
2176 * @cur: the initial node set
2177 * @val: the index to remove
2178 *
2179 * Removes an entry from an existing NodeSet list.
2180 */
2181void
2182xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2183 if (cur == NULL) return;
2184 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002185 if ((cur->nodeTab[val] != NULL) &&
2186 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2187 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002188 cur->nodeNr--;
2189 for (;val < cur->nodeNr;val++)
2190 cur->nodeTab[val] = cur->nodeTab[val + 1];
2191 cur->nodeTab[cur->nodeNr] = NULL;
2192}
2193
2194/**
2195 * xmlXPathFreeNodeSet:
2196 * @obj: the xmlNodeSetPtr to free
2197 *
2198 * Free the NodeSet compound (not the actual nodes !).
2199 */
2200void
2201xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2202 if (obj == NULL) return;
2203 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002204 int i;
2205
William M. Brack08171912003-12-29 02:52:11 +00002206 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002207 for (i = 0;i < obj->nodeNr;i++)
2208 if ((obj->nodeTab[i] != NULL) &&
2209 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2210 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002211 xmlFree(obj->nodeTab);
2212 }
Owen Taylor3473f882001-02-23 17:55:21 +00002213 xmlFree(obj);
2214}
2215
2216/**
2217 * xmlXPathFreeValueTree:
2218 * @obj: the xmlNodeSetPtr to free
2219 *
2220 * Free the NodeSet compound and the actual tree, this is different
2221 * from xmlXPathFreeNodeSet()
2222 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002223static void
Owen Taylor3473f882001-02-23 17:55:21 +00002224xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2225 int i;
2226
2227 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002228
2229 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002230 for (i = 0;i < obj->nodeNr;i++) {
2231 if (obj->nodeTab[i] != NULL) {
2232 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2233 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2234 } else {
2235 xmlFreeNodeList(obj->nodeTab[i]);
2236 }
2237 }
2238 }
Owen Taylor3473f882001-02-23 17:55:21 +00002239 xmlFree(obj->nodeTab);
2240 }
Owen Taylor3473f882001-02-23 17:55:21 +00002241 xmlFree(obj);
2242}
2243
2244#if defined(DEBUG) || defined(DEBUG_STEP)
2245/**
2246 * xmlGenericErrorContextNodeSet:
2247 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002248 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002249 *
2250 * Quick display of a NodeSet
2251 */
2252void
2253xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2254 int i;
2255
2256 if (output == NULL) output = xmlGenericErrorContext;
2257 if (obj == NULL) {
2258 fprintf(output, "NodeSet == NULL !\n");
2259 return;
2260 }
2261 if (obj->nodeNr == 0) {
2262 fprintf(output, "NodeSet is empty\n");
2263 return;
2264 }
2265 if (obj->nodeTab == NULL) {
2266 fprintf(output, " nodeTab == NULL !\n");
2267 return;
2268 }
2269 for (i = 0; i < obj->nodeNr; i++) {
2270 if (obj->nodeTab[i] == NULL) {
2271 fprintf(output, " NULL !\n");
2272 return;
2273 }
2274 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2275 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2276 fprintf(output, " /");
2277 else if (obj->nodeTab[i]->name == NULL)
2278 fprintf(output, " noname!");
2279 else fprintf(output, " %s", obj->nodeTab[i]->name);
2280 }
2281 fprintf(output, "\n");
2282}
2283#endif
2284
2285/**
2286 * xmlXPathNewNodeSet:
2287 * @val: the NodePtr value
2288 *
2289 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2290 * it with the single Node @val
2291 *
2292 * Returns the newly created object.
2293 */
2294xmlXPathObjectPtr
2295xmlXPathNewNodeSet(xmlNodePtr val) {
2296 xmlXPathObjectPtr ret;
2297
2298 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2299 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002300 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002301 return(NULL);
2302 }
2303 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2304 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002305 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002306 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002307 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002308 return(ret);
2309}
2310
2311/**
2312 * xmlXPathNewValueTree:
2313 * @val: the NodePtr value
2314 *
2315 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2316 * it with the tree root @val
2317 *
2318 * Returns the newly created object.
2319 */
2320xmlXPathObjectPtr
2321xmlXPathNewValueTree(xmlNodePtr val) {
2322 xmlXPathObjectPtr ret;
2323
2324 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2325 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002326 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002327 return(NULL);
2328 }
2329 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2330 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002331 ret->boolval = 1;
2332 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002333 ret->nodesetval = xmlXPathNodeSetCreate(val);
2334 return(ret);
2335}
2336
2337/**
2338 * xmlXPathNewNodeSetList:
2339 * @val: an existing NodeSet
2340 *
2341 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2342 * it with the Nodeset @val
2343 *
2344 * Returns the newly created object.
2345 */
2346xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002347xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2348{
Owen Taylor3473f882001-02-23 17:55:21 +00002349 xmlXPathObjectPtr ret;
2350 int i;
2351
2352 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002353 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002354 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002355 ret = xmlXPathNewNodeSet(NULL);
2356 else {
2357 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2358 for (i = 1; i < val->nodeNr; ++i)
2359 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2360 }
Owen Taylor3473f882001-02-23 17:55:21 +00002361
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002362 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002363}
2364
2365/**
2366 * xmlXPathWrapNodeSet:
2367 * @val: the NodePtr value
2368 *
2369 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2370 *
2371 * Returns the newly created object.
2372 */
2373xmlXPathObjectPtr
2374xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2375 xmlXPathObjectPtr ret;
2376
2377 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2378 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002379 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002380 return(NULL);
2381 }
2382 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2383 ret->type = XPATH_NODESET;
2384 ret->nodesetval = val;
2385 return(ret);
2386}
2387
2388/**
2389 * xmlXPathFreeNodeSetList:
2390 * @obj: an existing NodeSetList object
2391 *
2392 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2393 * the list contrary to xmlXPathFreeObject().
2394 */
2395void
2396xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2397 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002398 xmlFree(obj);
2399}
2400
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002401/**
2402 * xmlXPathDifference:
2403 * @nodes1: a node-set
2404 * @nodes2: a node-set
2405 *
2406 * Implements the EXSLT - Sets difference() function:
2407 * node-set set:difference (node-set, node-set)
2408 *
2409 * Returns the difference between the two node sets, or nodes1 if
2410 * nodes2 is empty
2411 */
2412xmlNodeSetPtr
2413xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2414 xmlNodeSetPtr ret;
2415 int i, l1;
2416 xmlNodePtr cur;
2417
2418 if (xmlXPathNodeSetIsEmpty(nodes2))
2419 return(nodes1);
2420
2421 ret = xmlXPathNodeSetCreate(NULL);
2422 if (xmlXPathNodeSetIsEmpty(nodes1))
2423 return(ret);
2424
2425 l1 = xmlXPathNodeSetGetLength(nodes1);
2426
2427 for (i = 0; i < l1; i++) {
2428 cur = xmlXPathNodeSetItem(nodes1, i);
2429 if (!xmlXPathNodeSetContains(nodes2, cur))
2430 xmlXPathNodeSetAddUnique(ret, cur);
2431 }
2432 return(ret);
2433}
2434
2435/**
2436 * xmlXPathIntersection:
2437 * @nodes1: a node-set
2438 * @nodes2: a node-set
2439 *
2440 * Implements the EXSLT - Sets intersection() function:
2441 * node-set set:intersection (node-set, node-set)
2442 *
2443 * Returns a node set comprising the nodes that are within both the
2444 * node sets passed as arguments
2445 */
2446xmlNodeSetPtr
2447xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2448 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2449 int i, l1;
2450 xmlNodePtr cur;
2451
2452 if (xmlXPathNodeSetIsEmpty(nodes1))
2453 return(ret);
2454 if (xmlXPathNodeSetIsEmpty(nodes2))
2455 return(ret);
2456
2457 l1 = xmlXPathNodeSetGetLength(nodes1);
2458
2459 for (i = 0; i < l1; i++) {
2460 cur = xmlXPathNodeSetItem(nodes1, i);
2461 if (xmlXPathNodeSetContains(nodes2, cur))
2462 xmlXPathNodeSetAddUnique(ret, cur);
2463 }
2464 return(ret);
2465}
2466
2467/**
2468 * xmlXPathDistinctSorted:
2469 * @nodes: a node-set, sorted by document order
2470 *
2471 * Implements the EXSLT - Sets distinct() function:
2472 * node-set set:distinct (node-set)
2473 *
2474 * Returns a subset of the nodes contained in @nodes, or @nodes if
2475 * it is empty
2476 */
2477xmlNodeSetPtr
2478xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2479 xmlNodeSetPtr ret;
2480 xmlHashTablePtr hash;
2481 int i, l;
2482 xmlChar * strval;
2483 xmlNodePtr cur;
2484
2485 if (xmlXPathNodeSetIsEmpty(nodes))
2486 return(nodes);
2487
2488 ret = xmlXPathNodeSetCreate(NULL);
2489 l = xmlXPathNodeSetGetLength(nodes);
2490 hash = xmlHashCreate (l);
2491 for (i = 0; i < l; i++) {
2492 cur = xmlXPathNodeSetItem(nodes, i);
2493 strval = xmlXPathCastNodeToString(cur);
2494 if (xmlHashLookup(hash, strval) == NULL) {
2495 xmlHashAddEntry(hash, strval, strval);
2496 xmlXPathNodeSetAddUnique(ret, cur);
2497 } else {
2498 xmlFree(strval);
2499 }
2500 }
2501 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2502 return(ret);
2503}
2504
2505/**
2506 * xmlXPathDistinct:
2507 * @nodes: a node-set
2508 *
2509 * Implements the EXSLT - Sets distinct() function:
2510 * node-set set:distinct (node-set)
2511 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2512 * is called with the sorted node-set
2513 *
2514 * Returns a subset of the nodes contained in @nodes, or @nodes if
2515 * it is empty
2516 */
2517xmlNodeSetPtr
2518xmlXPathDistinct (xmlNodeSetPtr nodes) {
2519 if (xmlXPathNodeSetIsEmpty(nodes))
2520 return(nodes);
2521
2522 xmlXPathNodeSetSort(nodes);
2523 return(xmlXPathDistinctSorted(nodes));
2524}
2525
2526/**
2527 * xmlXPathHasSameNodes:
2528 * @nodes1: a node-set
2529 * @nodes2: a node-set
2530 *
2531 * Implements the EXSLT - Sets has-same-nodes function:
2532 * boolean set:has-same-node(node-set, node-set)
2533 *
2534 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2535 * otherwise
2536 */
2537int
2538xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2539 int i, l;
2540 xmlNodePtr cur;
2541
2542 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2543 xmlXPathNodeSetIsEmpty(nodes2))
2544 return(0);
2545
2546 l = xmlXPathNodeSetGetLength(nodes1);
2547 for (i = 0; i < l; i++) {
2548 cur = xmlXPathNodeSetItem(nodes1, i);
2549 if (xmlXPathNodeSetContains(nodes2, cur))
2550 return(1);
2551 }
2552 return(0);
2553}
2554
2555/**
2556 * xmlXPathNodeLeadingSorted:
2557 * @nodes: a node-set, sorted by document order
2558 * @node: a node
2559 *
2560 * Implements the EXSLT - Sets leading() function:
2561 * node-set set:leading (node-set, node-set)
2562 *
2563 * Returns the nodes in @nodes that precede @node in document order,
2564 * @nodes if @node is NULL or an empty node-set if @nodes
2565 * doesn't contain @node
2566 */
2567xmlNodeSetPtr
2568xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2569 int i, l;
2570 xmlNodePtr cur;
2571 xmlNodeSetPtr ret;
2572
2573 if (node == NULL)
2574 return(nodes);
2575
2576 ret = xmlXPathNodeSetCreate(NULL);
2577 if (xmlXPathNodeSetIsEmpty(nodes) ||
2578 (!xmlXPathNodeSetContains(nodes, node)))
2579 return(ret);
2580
2581 l = xmlXPathNodeSetGetLength(nodes);
2582 for (i = 0; i < l; i++) {
2583 cur = xmlXPathNodeSetItem(nodes, i);
2584 if (cur == node)
2585 break;
2586 xmlXPathNodeSetAddUnique(ret, cur);
2587 }
2588 return(ret);
2589}
2590
2591/**
2592 * xmlXPathNodeLeading:
2593 * @nodes: a node-set
2594 * @node: a node
2595 *
2596 * Implements the EXSLT - Sets leading() function:
2597 * node-set set:leading (node-set, node-set)
2598 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2599 * is called.
2600 *
2601 * Returns the nodes in @nodes that precede @node in document order,
2602 * @nodes if @node is NULL or an empty node-set if @nodes
2603 * doesn't contain @node
2604 */
2605xmlNodeSetPtr
2606xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2607 xmlXPathNodeSetSort(nodes);
2608 return(xmlXPathNodeLeadingSorted(nodes, node));
2609}
2610
2611/**
2612 * xmlXPathLeadingSorted:
2613 * @nodes1: a node-set, sorted by document order
2614 * @nodes2: a node-set, sorted by document order
2615 *
2616 * Implements the EXSLT - Sets leading() function:
2617 * node-set set:leading (node-set, node-set)
2618 *
2619 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2620 * in document order, @nodes1 if @nodes2 is NULL or empty or
2621 * an empty node-set if @nodes1 doesn't contain @nodes2
2622 */
2623xmlNodeSetPtr
2624xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2625 if (xmlXPathNodeSetIsEmpty(nodes2))
2626 return(nodes1);
2627 return(xmlXPathNodeLeadingSorted(nodes1,
2628 xmlXPathNodeSetItem(nodes2, 1)));
2629}
2630
2631/**
2632 * xmlXPathLeading:
2633 * @nodes1: a node-set
2634 * @nodes2: a node-set
2635 *
2636 * Implements the EXSLT - Sets leading() function:
2637 * node-set set:leading (node-set, node-set)
2638 * @nodes1 and @nodes2 are sorted by document order, then
2639 * #exslSetsLeadingSorted is called.
2640 *
2641 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2642 * in document order, @nodes1 if @nodes2 is NULL or empty or
2643 * an empty node-set if @nodes1 doesn't contain @nodes2
2644 */
2645xmlNodeSetPtr
2646xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2647 if (xmlXPathNodeSetIsEmpty(nodes2))
2648 return(nodes1);
2649 if (xmlXPathNodeSetIsEmpty(nodes1))
2650 return(xmlXPathNodeSetCreate(NULL));
2651 xmlXPathNodeSetSort(nodes1);
2652 xmlXPathNodeSetSort(nodes2);
2653 return(xmlXPathNodeLeadingSorted(nodes1,
2654 xmlXPathNodeSetItem(nodes2, 1)));
2655}
2656
2657/**
2658 * xmlXPathNodeTrailingSorted:
2659 * @nodes: a node-set, sorted by document order
2660 * @node: a node
2661 *
2662 * Implements the EXSLT - Sets trailing() function:
2663 * node-set set:trailing (node-set, node-set)
2664 *
2665 * Returns the nodes in @nodes that follow @node in document order,
2666 * @nodes if @node is NULL or an empty node-set if @nodes
2667 * doesn't contain @node
2668 */
2669xmlNodeSetPtr
2670xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2671 int i, l;
2672 xmlNodePtr cur;
2673 xmlNodeSetPtr ret;
2674
2675 if (node == NULL)
2676 return(nodes);
2677
2678 ret = xmlXPathNodeSetCreate(NULL);
2679 if (xmlXPathNodeSetIsEmpty(nodes) ||
2680 (!xmlXPathNodeSetContains(nodes, node)))
2681 return(ret);
2682
2683 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002684 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002685 cur = xmlXPathNodeSetItem(nodes, i);
2686 if (cur == node)
2687 break;
2688 xmlXPathNodeSetAddUnique(ret, cur);
2689 }
2690 return(ret);
2691}
2692
2693/**
2694 * xmlXPathNodeTrailing:
2695 * @nodes: a node-set
2696 * @node: a node
2697 *
2698 * Implements the EXSLT - Sets trailing() function:
2699 * node-set set:trailing (node-set, node-set)
2700 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2701 * is called.
2702 *
2703 * Returns the nodes in @nodes that follow @node in document order,
2704 * @nodes if @node is NULL or an empty node-set if @nodes
2705 * doesn't contain @node
2706 */
2707xmlNodeSetPtr
2708xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2709 xmlXPathNodeSetSort(nodes);
2710 return(xmlXPathNodeTrailingSorted(nodes, node));
2711}
2712
2713/**
2714 * xmlXPathTrailingSorted:
2715 * @nodes1: a node-set, sorted by document order
2716 * @nodes2: a node-set, sorted by document order
2717 *
2718 * Implements the EXSLT - Sets trailing() function:
2719 * node-set set:trailing (node-set, node-set)
2720 *
2721 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2722 * in document order, @nodes1 if @nodes2 is NULL or empty or
2723 * an empty node-set if @nodes1 doesn't contain @nodes2
2724 */
2725xmlNodeSetPtr
2726xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2727 if (xmlXPathNodeSetIsEmpty(nodes2))
2728 return(nodes1);
2729 return(xmlXPathNodeTrailingSorted(nodes1,
2730 xmlXPathNodeSetItem(nodes2, 0)));
2731}
2732
2733/**
2734 * xmlXPathTrailing:
2735 * @nodes1: a node-set
2736 * @nodes2: a node-set
2737 *
2738 * Implements the EXSLT - Sets trailing() function:
2739 * node-set set:trailing (node-set, node-set)
2740 * @nodes1 and @nodes2 are sorted by document order, then
2741 * #xmlXPathTrailingSorted is called.
2742 *
2743 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2744 * in document order, @nodes1 if @nodes2 is NULL or empty or
2745 * an empty node-set if @nodes1 doesn't contain @nodes2
2746 */
2747xmlNodeSetPtr
2748xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2749 if (xmlXPathNodeSetIsEmpty(nodes2))
2750 return(nodes1);
2751 if (xmlXPathNodeSetIsEmpty(nodes1))
2752 return(xmlXPathNodeSetCreate(NULL));
2753 xmlXPathNodeSetSort(nodes1);
2754 xmlXPathNodeSetSort(nodes2);
2755 return(xmlXPathNodeTrailingSorted(nodes1,
2756 xmlXPathNodeSetItem(nodes2, 0)));
2757}
2758
Owen Taylor3473f882001-02-23 17:55:21 +00002759/************************************************************************
2760 * *
2761 * Routines to handle extra functions *
2762 * *
2763 ************************************************************************/
2764
2765/**
2766 * xmlXPathRegisterFunc:
2767 * @ctxt: the XPath context
2768 * @name: the function name
2769 * @f: the function implementation or NULL
2770 *
2771 * Register a new function. If @f is NULL it unregisters the function
2772 *
2773 * Returns 0 in case of success, -1 in case of error
2774 */
2775int
2776xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2777 xmlXPathFunction f) {
2778 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2779}
2780
2781/**
2782 * xmlXPathRegisterFuncNS:
2783 * @ctxt: the XPath context
2784 * @name: the function name
2785 * @ns_uri: the function namespace URI
2786 * @f: the function implementation or NULL
2787 *
2788 * Register a new function. If @f is NULL it unregisters the function
2789 *
2790 * Returns 0 in case of success, -1 in case of error
2791 */
2792int
2793xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2794 const xmlChar *ns_uri, xmlXPathFunction f) {
2795 if (ctxt == NULL)
2796 return(-1);
2797 if (name == NULL)
2798 return(-1);
2799
2800 if (ctxt->funcHash == NULL)
2801 ctxt->funcHash = xmlHashCreate(0);
2802 if (ctxt->funcHash == NULL)
2803 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002804 if (f == NULL)
2805 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
Owen Taylor3473f882001-02-23 17:55:21 +00002806 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2807}
2808
2809/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002810 * xmlXPathRegisterFuncLookup:
2811 * @ctxt: the XPath context
2812 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002813 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002814 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002815 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002816 */
2817void
2818xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2819 xmlXPathFuncLookupFunc f,
2820 void *funcCtxt) {
2821 if (ctxt == NULL)
2822 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002823 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002824 ctxt->funcLookupData = funcCtxt;
2825}
2826
2827/**
Owen Taylor3473f882001-02-23 17:55:21 +00002828 * xmlXPathFunctionLookup:
2829 * @ctxt: the XPath context
2830 * @name: the function name
2831 *
2832 * Search in the Function array of the context for the given
2833 * function.
2834 *
2835 * Returns the xmlXPathFunction or NULL if not found
2836 */
2837xmlXPathFunction
2838xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002839 if (ctxt == NULL)
2840 return (NULL);
2841
2842 if (ctxt->funcLookupFunc != NULL) {
2843 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002844 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002845
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002846 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002847 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002848 if (ret != NULL)
2849 return(ret);
2850 }
Owen Taylor3473f882001-02-23 17:55:21 +00002851 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2852}
2853
2854/**
2855 * xmlXPathFunctionLookupNS:
2856 * @ctxt: the XPath context
2857 * @name: the function name
2858 * @ns_uri: the function namespace URI
2859 *
2860 * Search in the Function array of the context for the given
2861 * function.
2862 *
2863 * Returns the xmlXPathFunction or NULL if not found
2864 */
2865xmlXPathFunction
2866xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2867 const xmlChar *ns_uri) {
2868 if (ctxt == NULL)
2869 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002870 if (name == NULL)
2871 return(NULL);
2872
Thomas Broyerba4ad322001-07-26 16:55:21 +00002873 if (ctxt->funcLookupFunc != NULL) {
2874 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002875 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002876
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002877 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002878 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002879 if (ret != NULL)
2880 return(ret);
2881 }
2882
2883 if (ctxt->funcHash == NULL)
2884 return(NULL);
2885
Owen Taylor3473f882001-02-23 17:55:21 +00002886 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2887}
2888
2889/**
2890 * xmlXPathRegisteredFuncsCleanup:
2891 * @ctxt: the XPath context
2892 *
2893 * Cleanup the XPath context data associated to registered functions
2894 */
2895void
2896xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2897 if (ctxt == NULL)
2898 return;
2899
2900 xmlHashFree(ctxt->funcHash, NULL);
2901 ctxt->funcHash = NULL;
2902}
2903
2904/************************************************************************
2905 * *
William M. Brack08171912003-12-29 02:52:11 +00002906 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00002907 * *
2908 ************************************************************************/
2909
2910/**
2911 * xmlXPathRegisterVariable:
2912 * @ctxt: the XPath context
2913 * @name: the variable name
2914 * @value: the variable value or NULL
2915 *
2916 * Register a new variable value. If @value is NULL it unregisters
2917 * the variable
2918 *
2919 * Returns 0 in case of success, -1 in case of error
2920 */
2921int
2922xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2923 xmlXPathObjectPtr value) {
2924 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2925}
2926
2927/**
2928 * xmlXPathRegisterVariableNS:
2929 * @ctxt: the XPath context
2930 * @name: the variable name
2931 * @ns_uri: the variable namespace URI
2932 * @value: the variable value or NULL
2933 *
2934 * Register a new variable value. If @value is NULL it unregisters
2935 * the variable
2936 *
2937 * Returns 0 in case of success, -1 in case of error
2938 */
2939int
2940xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2941 const xmlChar *ns_uri,
2942 xmlXPathObjectPtr value) {
2943 if (ctxt == NULL)
2944 return(-1);
2945 if (name == NULL)
2946 return(-1);
2947
2948 if (ctxt->varHash == NULL)
2949 ctxt->varHash = xmlHashCreate(0);
2950 if (ctxt->varHash == NULL)
2951 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002952 if (value == NULL)
2953 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2954 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002955 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2956 (void *) value,
2957 (xmlHashDeallocator)xmlXPathFreeObject));
2958}
2959
2960/**
2961 * xmlXPathRegisterVariableLookup:
2962 * @ctxt: the XPath context
2963 * @f: the lookup function
2964 * @data: the lookup data
2965 *
2966 * register an external mechanism to do variable lookup
2967 */
2968void
2969xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2970 xmlXPathVariableLookupFunc f, void *data) {
2971 if (ctxt == NULL)
2972 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002973 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00002974 ctxt->varLookupData = data;
2975}
2976
2977/**
2978 * xmlXPathVariableLookup:
2979 * @ctxt: the XPath context
2980 * @name: the variable name
2981 *
2982 * Search in the Variable array of the context for the given
2983 * variable value.
2984 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002985 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002986 */
2987xmlXPathObjectPtr
2988xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2989 if (ctxt == NULL)
2990 return(NULL);
2991
2992 if (ctxt->varLookupFunc != NULL) {
2993 xmlXPathObjectPtr ret;
2994
2995 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2996 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002997 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002998 }
2999 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3000}
3001
3002/**
3003 * xmlXPathVariableLookupNS:
3004 * @ctxt: the XPath context
3005 * @name: the variable name
3006 * @ns_uri: the variable namespace URI
3007 *
3008 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00003009 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00003010 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003011 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003012 */
3013xmlXPathObjectPtr
3014xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3015 const xmlChar *ns_uri) {
3016 if (ctxt == NULL)
3017 return(NULL);
3018
3019 if (ctxt->varLookupFunc != NULL) {
3020 xmlXPathObjectPtr ret;
3021
3022 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3023 (ctxt->varLookupData, name, ns_uri);
3024 if (ret != NULL) return(ret);
3025 }
3026
3027 if (ctxt->varHash == NULL)
3028 return(NULL);
3029 if (name == NULL)
3030 return(NULL);
3031
Daniel Veillard8c357d52001-07-03 23:43:33 +00003032 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3033 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00003034}
3035
3036/**
3037 * xmlXPathRegisteredVariablesCleanup:
3038 * @ctxt: the XPath context
3039 *
3040 * Cleanup the XPath context data associated to registered variables
3041 */
3042void
3043xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3044 if (ctxt == NULL)
3045 return;
3046
Daniel Veillard76d66f42001-05-16 21:05:17 +00003047 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00003048 ctxt->varHash = NULL;
3049}
3050
3051/**
3052 * xmlXPathRegisterNs:
3053 * @ctxt: the XPath context
3054 * @prefix: the namespace prefix
3055 * @ns_uri: the namespace name
3056 *
3057 * Register a new namespace. If @ns_uri is NULL it unregisters
3058 * the namespace
3059 *
3060 * Returns 0 in case of success, -1 in case of error
3061 */
3062int
3063xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3064 const xmlChar *ns_uri) {
3065 if (ctxt == NULL)
3066 return(-1);
3067 if (prefix == NULL)
3068 return(-1);
3069
3070 if (ctxt->nsHash == NULL)
3071 ctxt->nsHash = xmlHashCreate(10);
3072 if (ctxt->nsHash == NULL)
3073 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003074 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003075 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003076 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003077 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003078 (xmlHashDeallocator)xmlFree));
3079}
3080
3081/**
3082 * xmlXPathNsLookup:
3083 * @ctxt: the XPath context
3084 * @prefix: the namespace prefix value
3085 *
3086 * Search in the namespace declaration array of the context for the given
3087 * namespace name associated to the given prefix
3088 *
3089 * Returns the value or NULL if not found
3090 */
3091const xmlChar *
3092xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3093 if (ctxt == NULL)
3094 return(NULL);
3095 if (prefix == NULL)
3096 return(NULL);
3097
3098#ifdef XML_XML_NAMESPACE
3099 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3100 return(XML_XML_NAMESPACE);
3101#endif
3102
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003103 if (ctxt->namespaces != NULL) {
3104 int i;
3105
3106 for (i = 0;i < ctxt->nsNr;i++) {
3107 if ((ctxt->namespaces[i] != NULL) &&
3108 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3109 return(ctxt->namespaces[i]->href);
3110 }
3111 }
Owen Taylor3473f882001-02-23 17:55:21 +00003112
3113 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3114}
3115
3116/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003117 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003118 * @ctxt: the XPath context
3119 *
3120 * Cleanup the XPath context data associated to registered variables
3121 */
3122void
3123xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3124 if (ctxt == NULL)
3125 return;
3126
Daniel Veillard42766c02002-08-22 20:52:17 +00003127 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003128 ctxt->nsHash = NULL;
3129}
3130
3131/************************************************************************
3132 * *
3133 * Routines to handle Values *
3134 * *
3135 ************************************************************************/
3136
William M. Brack08171912003-12-29 02:52:11 +00003137/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003138
3139/**
3140 * xmlXPathNewFloat:
3141 * @val: the double value
3142 *
3143 * Create a new xmlXPathObjectPtr of type double and of value @val
3144 *
3145 * Returns the newly created object.
3146 */
3147xmlXPathObjectPtr
3148xmlXPathNewFloat(double val) {
3149 xmlXPathObjectPtr ret;
3150
3151 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3152 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003153 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003154 return(NULL);
3155 }
3156 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3157 ret->type = XPATH_NUMBER;
3158 ret->floatval = val;
3159 return(ret);
3160}
3161
3162/**
3163 * xmlXPathNewBoolean:
3164 * @val: the boolean value
3165 *
3166 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3167 *
3168 * Returns the newly created object.
3169 */
3170xmlXPathObjectPtr
3171xmlXPathNewBoolean(int val) {
3172 xmlXPathObjectPtr ret;
3173
3174 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3175 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003176 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003177 return(NULL);
3178 }
3179 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3180 ret->type = XPATH_BOOLEAN;
3181 ret->boolval = (val != 0);
3182 return(ret);
3183}
3184
3185/**
3186 * xmlXPathNewString:
3187 * @val: the xmlChar * value
3188 *
3189 * Create a new xmlXPathObjectPtr of type string and of value @val
3190 *
3191 * Returns the newly created object.
3192 */
3193xmlXPathObjectPtr
3194xmlXPathNewString(const xmlChar *val) {
3195 xmlXPathObjectPtr ret;
3196
3197 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3198 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003199 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003200 return(NULL);
3201 }
3202 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3203 ret->type = XPATH_STRING;
3204 if (val != NULL)
3205 ret->stringval = xmlStrdup(val);
3206 else
3207 ret->stringval = xmlStrdup((const xmlChar *)"");
3208 return(ret);
3209}
3210
3211/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003212 * xmlXPathWrapString:
3213 * @val: the xmlChar * value
3214 *
3215 * Wraps the @val string into an XPath object.
3216 *
3217 * Returns the newly created object.
3218 */
3219xmlXPathObjectPtr
3220xmlXPathWrapString (xmlChar *val) {
3221 xmlXPathObjectPtr ret;
3222
3223 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3224 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003225 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003226 return(NULL);
3227 }
3228 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3229 ret->type = XPATH_STRING;
3230 ret->stringval = val;
3231 return(ret);
3232}
3233
3234/**
Owen Taylor3473f882001-02-23 17:55:21 +00003235 * xmlXPathNewCString:
3236 * @val: the char * value
3237 *
3238 * Create a new xmlXPathObjectPtr of type string and of value @val
3239 *
3240 * Returns the newly created object.
3241 */
3242xmlXPathObjectPtr
3243xmlXPathNewCString(const char *val) {
3244 xmlXPathObjectPtr ret;
3245
3246 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3247 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003248 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003249 return(NULL);
3250 }
3251 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3252 ret->type = XPATH_STRING;
3253 ret->stringval = xmlStrdup(BAD_CAST val);
3254 return(ret);
3255}
3256
3257/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003258 * xmlXPathWrapCString:
3259 * @val: the char * value
3260 *
3261 * Wraps a string into an XPath object.
3262 *
3263 * Returns the newly created object.
3264 */
3265xmlXPathObjectPtr
3266xmlXPathWrapCString (char * val) {
3267 return(xmlXPathWrapString((xmlChar *)(val)));
3268}
3269
3270/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003271 * xmlXPathWrapExternal:
3272 * @val: the user data
3273 *
3274 * Wraps the @val data into an XPath object.
3275 *
3276 * Returns the newly created object.
3277 */
3278xmlXPathObjectPtr
3279xmlXPathWrapExternal (void *val) {
3280 xmlXPathObjectPtr ret;
3281
3282 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3283 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003284 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003285 return(NULL);
3286 }
3287 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3288 ret->type = XPATH_USERS;
3289 ret->user = val;
3290 return(ret);
3291}
3292
3293/**
Owen Taylor3473f882001-02-23 17:55:21 +00003294 * xmlXPathObjectCopy:
3295 * @val: the original object
3296 *
3297 * allocate a new copy of a given object
3298 *
3299 * Returns the newly created object.
3300 */
3301xmlXPathObjectPtr
3302xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3303 xmlXPathObjectPtr ret;
3304
3305 if (val == NULL)
3306 return(NULL);
3307
3308 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3309 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003310 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003311 return(NULL);
3312 }
3313 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3314 switch (val->type) {
3315 case XPATH_BOOLEAN:
3316 case XPATH_NUMBER:
3317 case XPATH_POINT:
3318 case XPATH_RANGE:
3319 break;
3320 case XPATH_STRING:
3321 ret->stringval = xmlStrdup(val->stringval);
3322 break;
3323 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00003324#if 0
3325/*
3326 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
3327 this previous handling is no longer correct, and can cause some serious
3328 problems (ref. bug 145547)
3329*/
Owen Taylor3473f882001-02-23 17:55:21 +00003330 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003331 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003332 xmlNodePtr cur, tmp;
3333 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003334
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003335 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003336 top = xmlNewDoc(NULL);
3337 top->name = (char *)
3338 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003339 ret->user = top;
3340 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003341 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003342 cur = val->nodesetval->nodeTab[0]->children;
3343 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003344 tmp = xmlDocCopyNode(cur, top, 1);
3345 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003346 cur = cur->next;
3347 }
3348 }
William M. Bracke9449c52004-07-11 14:41:20 +00003349
Daniel Veillard9adc0462003-03-24 18:39:54 +00003350 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003351 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003352 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003353 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003354 break;
William M. Bracke9449c52004-07-11 14:41:20 +00003355#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003356 case XPATH_NODESET:
3357 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003358 /* Do not deallocate the copied tree value */
3359 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003360 break;
3361 case XPATH_LOCATIONSET:
3362#ifdef LIBXML_XPTR_ENABLED
3363 {
3364 xmlLocationSetPtr loc = val->user;
3365 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3366 break;
3367 }
3368#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003369 case XPATH_USERS:
3370 ret->user = val->user;
3371 break;
3372 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003373 xmlGenericError(xmlGenericErrorContext,
3374 "xmlXPathObjectCopy: unsupported type %d\n",
3375 val->type);
3376 break;
3377 }
3378 return(ret);
3379}
3380
3381/**
3382 * xmlXPathFreeObject:
3383 * @obj: the object to free
3384 *
3385 * Free up an xmlXPathObjectPtr object.
3386 */
3387void
3388xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3389 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003390 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003391 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00003392#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003393 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003394 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003395 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003396 } else
3397#endif
3398 if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003399 xmlXPathFreeValueTree(obj->nodesetval);
3400 } else {
3401 if (obj->nodesetval != NULL)
3402 xmlXPathFreeNodeSet(obj->nodesetval);
3403 }
Owen Taylor3473f882001-02-23 17:55:21 +00003404#ifdef LIBXML_XPTR_ENABLED
3405 } else if (obj->type == XPATH_LOCATIONSET) {
3406 if (obj->user != NULL)
3407 xmlXPtrFreeLocationSet(obj->user);
3408#endif
3409 } else if (obj->type == XPATH_STRING) {
3410 if (obj->stringval != NULL)
3411 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003412 }
3413
Owen Taylor3473f882001-02-23 17:55:21 +00003414 xmlFree(obj);
3415}
3416
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003417
3418/************************************************************************
3419 * *
3420 * Type Casting Routines *
3421 * *
3422 ************************************************************************/
3423
3424/**
3425 * xmlXPathCastBooleanToString:
3426 * @val: a boolean
3427 *
3428 * Converts a boolean to its string value.
3429 *
3430 * Returns a newly allocated string.
3431 */
3432xmlChar *
3433xmlXPathCastBooleanToString (int val) {
3434 xmlChar *ret;
3435 if (val)
3436 ret = xmlStrdup((const xmlChar *) "true");
3437 else
3438 ret = xmlStrdup((const xmlChar *) "false");
3439 return(ret);
3440}
3441
3442/**
3443 * xmlXPathCastNumberToString:
3444 * @val: a number
3445 *
3446 * Converts a number to its string value.
3447 *
3448 * Returns a newly allocated string.
3449 */
3450xmlChar *
3451xmlXPathCastNumberToString (double val) {
3452 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003453 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003454 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003455 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003456 break;
3457 case -1:
3458 ret = xmlStrdup((const xmlChar *) "-Infinity");
3459 break;
3460 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003461 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003462 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003463 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3464 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003465 } else {
3466 /* could be improved */
3467 char buf[100];
3468 xmlXPathFormatNumber(val, buf, 100);
3469 ret = xmlStrdup((const xmlChar *) buf);
3470 }
3471 }
3472 return(ret);
3473}
3474
3475/**
3476 * xmlXPathCastNodeToString:
3477 * @node: a node
3478 *
3479 * Converts a node to its string value.
3480 *
3481 * Returns a newly allocated string.
3482 */
3483xmlChar *
3484xmlXPathCastNodeToString (xmlNodePtr node) {
3485 return(xmlNodeGetContent(node));
3486}
3487
3488/**
3489 * xmlXPathCastNodeSetToString:
3490 * @ns: a node-set
3491 *
3492 * Converts a node-set to its string value.
3493 *
3494 * Returns a newly allocated string.
3495 */
3496xmlChar *
3497xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3498 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3499 return(xmlStrdup((const xmlChar *) ""));
3500
3501 xmlXPathNodeSetSort(ns);
3502 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3503}
3504
3505/**
3506 * xmlXPathCastToString:
3507 * @val: an XPath object
3508 *
3509 * Converts an existing object to its string() equivalent
3510 *
3511 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003512 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003513 * string object).
3514 */
3515xmlChar *
3516xmlXPathCastToString(xmlXPathObjectPtr val) {
3517 xmlChar *ret = NULL;
3518
3519 if (val == NULL)
3520 return(xmlStrdup((const xmlChar *) ""));
3521 switch (val->type) {
3522 case XPATH_UNDEFINED:
3523#ifdef DEBUG_EXPR
3524 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3525#endif
3526 ret = xmlStrdup((const xmlChar *) "");
3527 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003528 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003529 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003530 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3531 break;
3532 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003533 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003534 case XPATH_BOOLEAN:
3535 ret = xmlXPathCastBooleanToString(val->boolval);
3536 break;
3537 case XPATH_NUMBER: {
3538 ret = xmlXPathCastNumberToString(val->floatval);
3539 break;
3540 }
3541 case XPATH_USERS:
3542 case XPATH_POINT:
3543 case XPATH_RANGE:
3544 case XPATH_LOCATIONSET:
3545 TODO
3546 ret = xmlStrdup((const xmlChar *) "");
3547 break;
3548 }
3549 return(ret);
3550}
3551
3552/**
3553 * xmlXPathConvertString:
3554 * @val: an XPath object
3555 *
3556 * Converts an existing object to its string() equivalent
3557 *
3558 * Returns the new object, the old one is freed (or the operation
3559 * is done directly on @val)
3560 */
3561xmlXPathObjectPtr
3562xmlXPathConvertString(xmlXPathObjectPtr val) {
3563 xmlChar *res = NULL;
3564
3565 if (val == NULL)
3566 return(xmlXPathNewCString(""));
3567
3568 switch (val->type) {
3569 case XPATH_UNDEFINED:
3570#ifdef DEBUG_EXPR
3571 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3572#endif
3573 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003574 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003575 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003576 res = xmlXPathCastNodeSetToString(val->nodesetval);
3577 break;
3578 case XPATH_STRING:
3579 return(val);
3580 case XPATH_BOOLEAN:
3581 res = xmlXPathCastBooleanToString(val->boolval);
3582 break;
3583 case XPATH_NUMBER:
3584 res = xmlXPathCastNumberToString(val->floatval);
3585 break;
3586 case XPATH_USERS:
3587 case XPATH_POINT:
3588 case XPATH_RANGE:
3589 case XPATH_LOCATIONSET:
3590 TODO;
3591 break;
3592 }
3593 xmlXPathFreeObject(val);
3594 if (res == NULL)
3595 return(xmlXPathNewCString(""));
3596 return(xmlXPathWrapString(res));
3597}
3598
3599/**
3600 * xmlXPathCastBooleanToNumber:
3601 * @val: a boolean
3602 *
3603 * Converts a boolean to its number value
3604 *
3605 * Returns the number value
3606 */
3607double
3608xmlXPathCastBooleanToNumber(int val) {
3609 if (val)
3610 return(1.0);
3611 return(0.0);
3612}
3613
3614/**
3615 * xmlXPathCastStringToNumber:
3616 * @val: a string
3617 *
3618 * Converts a string to its number value
3619 *
3620 * Returns the number value
3621 */
3622double
3623xmlXPathCastStringToNumber(const xmlChar * val) {
3624 return(xmlXPathStringEvalNumber(val));
3625}
3626
3627/**
3628 * xmlXPathCastNodeToNumber:
3629 * @node: a node
3630 *
3631 * Converts a node to its number value
3632 *
3633 * Returns the number value
3634 */
3635double
3636xmlXPathCastNodeToNumber (xmlNodePtr node) {
3637 xmlChar *strval;
3638 double ret;
3639
3640 if (node == NULL)
3641 return(xmlXPathNAN);
3642 strval = xmlXPathCastNodeToString(node);
3643 if (strval == NULL)
3644 return(xmlXPathNAN);
3645 ret = xmlXPathCastStringToNumber(strval);
3646 xmlFree(strval);
3647
3648 return(ret);
3649}
3650
3651/**
3652 * xmlXPathCastNodeSetToNumber:
3653 * @ns: a node-set
3654 *
3655 * Converts a node-set to its number value
3656 *
3657 * Returns the number value
3658 */
3659double
3660xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3661 xmlChar *str;
3662 double ret;
3663
3664 if (ns == NULL)
3665 return(xmlXPathNAN);
3666 str = xmlXPathCastNodeSetToString(ns);
3667 ret = xmlXPathCastStringToNumber(str);
3668 xmlFree(str);
3669 return(ret);
3670}
3671
3672/**
3673 * xmlXPathCastToNumber:
3674 * @val: an XPath object
3675 *
3676 * Converts an XPath object to its number value
3677 *
3678 * Returns the number value
3679 */
3680double
3681xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3682 double ret = 0.0;
3683
3684 if (val == NULL)
3685 return(xmlXPathNAN);
3686 switch (val->type) {
3687 case XPATH_UNDEFINED:
3688#ifdef DEGUB_EXPR
3689 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3690#endif
3691 ret = xmlXPathNAN;
3692 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003693 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003694 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003695 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3696 break;
3697 case XPATH_STRING:
3698 ret = xmlXPathCastStringToNumber(val->stringval);
3699 break;
3700 case XPATH_NUMBER:
3701 ret = val->floatval;
3702 break;
3703 case XPATH_BOOLEAN:
3704 ret = xmlXPathCastBooleanToNumber(val->boolval);
3705 break;
3706 case XPATH_USERS:
3707 case XPATH_POINT:
3708 case XPATH_RANGE:
3709 case XPATH_LOCATIONSET:
3710 TODO;
3711 ret = xmlXPathNAN;
3712 break;
3713 }
3714 return(ret);
3715}
3716
3717/**
3718 * xmlXPathConvertNumber:
3719 * @val: an XPath object
3720 *
3721 * Converts an existing object to its number() equivalent
3722 *
3723 * Returns the new object, the old one is freed (or the operation
3724 * is done directly on @val)
3725 */
3726xmlXPathObjectPtr
3727xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3728 xmlXPathObjectPtr ret;
3729
3730 if (val == NULL)
3731 return(xmlXPathNewFloat(0.0));
3732 if (val->type == XPATH_NUMBER)
3733 return(val);
3734 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3735 xmlXPathFreeObject(val);
3736 return(ret);
3737}
3738
3739/**
3740 * xmlXPathCastNumberToBoolean:
3741 * @val: a number
3742 *
3743 * Converts a number to its boolean value
3744 *
3745 * Returns the boolean value
3746 */
3747int
3748xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003749 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003750 return(0);
3751 return(1);
3752}
3753
3754/**
3755 * xmlXPathCastStringToBoolean:
3756 * @val: a string
3757 *
3758 * Converts a string to its boolean value
3759 *
3760 * Returns the boolean value
3761 */
3762int
3763xmlXPathCastStringToBoolean (const xmlChar *val) {
3764 if ((val == NULL) || (xmlStrlen(val) == 0))
3765 return(0);
3766 return(1);
3767}
3768
3769/**
3770 * xmlXPathCastNodeSetToBoolean:
3771 * @ns: a node-set
3772 *
3773 * Converts a node-set to its boolean value
3774 *
3775 * Returns the boolean value
3776 */
3777int
3778xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3779 if ((ns == NULL) || (ns->nodeNr == 0))
3780 return(0);
3781 return(1);
3782}
3783
3784/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003785 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003786 * @val: an XPath object
3787 *
3788 * Converts an XPath object to its boolean value
3789 *
3790 * Returns the boolean value
3791 */
3792int
3793xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3794 int ret = 0;
3795
3796 if (val == NULL)
3797 return(0);
3798 switch (val->type) {
3799 case XPATH_UNDEFINED:
3800#ifdef DEBUG_EXPR
3801 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3802#endif
3803 ret = 0;
3804 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003805 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003806 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003807 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3808 break;
3809 case XPATH_STRING:
3810 ret = xmlXPathCastStringToBoolean(val->stringval);
3811 break;
3812 case XPATH_NUMBER:
3813 ret = xmlXPathCastNumberToBoolean(val->floatval);
3814 break;
3815 case XPATH_BOOLEAN:
3816 ret = val->boolval;
3817 break;
3818 case XPATH_USERS:
3819 case XPATH_POINT:
3820 case XPATH_RANGE:
3821 case XPATH_LOCATIONSET:
3822 TODO;
3823 ret = 0;
3824 break;
3825 }
3826 return(ret);
3827}
3828
3829
3830/**
3831 * xmlXPathConvertBoolean:
3832 * @val: an XPath object
3833 *
3834 * Converts an existing object to its boolean() equivalent
3835 *
3836 * Returns the new object, the old one is freed (or the operation
3837 * is done directly on @val)
3838 */
3839xmlXPathObjectPtr
3840xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3841 xmlXPathObjectPtr ret;
3842
3843 if (val == NULL)
3844 return(xmlXPathNewBoolean(0));
3845 if (val->type == XPATH_BOOLEAN)
3846 return(val);
3847 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3848 xmlXPathFreeObject(val);
3849 return(ret);
3850}
3851
Owen Taylor3473f882001-02-23 17:55:21 +00003852/************************************************************************
3853 * *
3854 * Routines to handle XPath contexts *
3855 * *
3856 ************************************************************************/
3857
3858/**
3859 * xmlXPathNewContext:
3860 * @doc: the XML document
3861 *
3862 * Create a new xmlXPathContext
3863 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003864 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003865 */
3866xmlXPathContextPtr
3867xmlXPathNewContext(xmlDocPtr doc) {
3868 xmlXPathContextPtr ret;
3869
3870 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3871 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003872 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003873 return(NULL);
3874 }
3875 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3876 ret->doc = doc;
3877 ret->node = NULL;
3878
3879 ret->varHash = NULL;
3880
3881 ret->nb_types = 0;
3882 ret->max_types = 0;
3883 ret->types = NULL;
3884
3885 ret->funcHash = xmlHashCreate(0);
3886
3887 ret->nb_axis = 0;
3888 ret->max_axis = 0;
3889 ret->axis = NULL;
3890
3891 ret->nsHash = NULL;
3892 ret->user = NULL;
3893
3894 ret->contextSize = -1;
3895 ret->proximityPosition = -1;
3896
3897 xmlXPathRegisterAllFunctions(ret);
3898
3899 return(ret);
3900}
3901
3902/**
3903 * xmlXPathFreeContext:
3904 * @ctxt: the context to free
3905 *
3906 * Free up an xmlXPathContext
3907 */
3908void
3909xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3910 xmlXPathRegisteredNsCleanup(ctxt);
3911 xmlXPathRegisteredFuncsCleanup(ctxt);
3912 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003913 xmlFree(ctxt);
3914}
3915
3916/************************************************************************
3917 * *
3918 * Routines to handle XPath parser contexts *
3919 * *
3920 ************************************************************************/
3921
3922#define CHECK_CTXT(ctxt) \
3923 if (ctxt == NULL) { \
3924 xmlGenericError(xmlGenericErrorContext, \
3925 "%s:%d Internal error: ctxt == NULL\n", \
3926 __FILE__, __LINE__); \
3927 } \
3928
3929
3930#define CHECK_CONTEXT(ctxt) \
3931 if (ctxt == NULL) { \
3932 xmlGenericError(xmlGenericErrorContext, \
3933 "%s:%d Internal error: no context\n", \
3934 __FILE__, __LINE__); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00003935 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00003936 } \
3937 else if (ctxt->doc == NULL) { \
3938 xmlGenericError(xmlGenericErrorContext, \
3939 "%s:%d Internal error: no document\n", \
3940 __FILE__, __LINE__); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00003941 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00003942 } \
3943 else if (ctxt->doc->children == NULL) { \
3944 xmlGenericError(xmlGenericErrorContext, \
3945 "%s:%d Internal error: document without root\n", \
3946 __FILE__, __LINE__); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00003947 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00003948 } \
3949
3950
3951/**
3952 * xmlXPathNewParserContext:
3953 * @str: the XPath expression
3954 * @ctxt: the XPath context
3955 *
3956 * Create a new xmlXPathParserContext
3957 *
3958 * Returns the xmlXPathParserContext just allocated.
3959 */
3960xmlXPathParserContextPtr
3961xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3962 xmlXPathParserContextPtr ret;
3963
3964 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3965 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003966 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003967 return(NULL);
3968 }
3969 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3970 ret->cur = ret->base = str;
3971 ret->context = ctxt;
3972
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003973 ret->comp = xmlXPathNewCompExpr();
3974 if (ret->comp == NULL) {
3975 xmlFree(ret->valueTab);
3976 xmlFree(ret);
3977 return(NULL);
3978 }
Daniel Veillard4773df22004-01-23 13:15:13 +00003979 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
3980 ret->comp->dict = ctxt->dict;
3981 xmlDictReference(ret->comp->dict);
3982 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003983
3984 return(ret);
3985}
3986
3987/**
3988 * xmlXPathCompParserContext:
3989 * @comp: the XPath compiled expression
3990 * @ctxt: the XPath context
3991 *
3992 * Create a new xmlXPathParserContext when processing a compiled expression
3993 *
3994 * Returns the xmlXPathParserContext just allocated.
3995 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003996static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003997xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3998 xmlXPathParserContextPtr ret;
3999
4000 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4001 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004002 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004003 return(NULL);
4004 }
4005 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4006
Owen Taylor3473f882001-02-23 17:55:21 +00004007 /* Allocate the value stack */
4008 ret->valueTab = (xmlXPathObjectPtr *)
4009 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004010 if (ret->valueTab == NULL) {
4011 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004012 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004013 return(NULL);
4014 }
Owen Taylor3473f882001-02-23 17:55:21 +00004015 ret->valueNr = 0;
4016 ret->valueMax = 10;
4017 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004018
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004019 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004020 ret->comp = comp;
4021
Owen Taylor3473f882001-02-23 17:55:21 +00004022 return(ret);
4023}
4024
4025/**
4026 * xmlXPathFreeParserContext:
4027 * @ctxt: the context to free
4028 *
4029 * Free up an xmlXPathParserContext
4030 */
4031void
4032xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
4033 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004034 xmlFree(ctxt->valueTab);
4035 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004036 if (ctxt->comp)
4037 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00004038 xmlFree(ctxt);
4039}
4040
4041/************************************************************************
4042 * *
4043 * The implicit core function library *
4044 * *
4045 ************************************************************************/
4046
Owen Taylor3473f882001-02-23 17:55:21 +00004047/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004048 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00004049 * @node: a node pointer
4050 *
4051 * Function computing the beginning of the string value of the node,
4052 * used to speed up comparisons
4053 *
4054 * Returns an int usable as a hash
4055 */
4056static unsigned int
4057xmlXPathNodeValHash(xmlNodePtr node) {
4058 int len = 2;
4059 const xmlChar * string = NULL;
4060 xmlNodePtr tmp = NULL;
4061 unsigned int ret = 0;
4062
4063 if (node == NULL)
4064 return(0);
4065
Daniel Veillard9adc0462003-03-24 18:39:54 +00004066 if (node->type == XML_DOCUMENT_NODE) {
4067 tmp = xmlDocGetRootElement((xmlDocPtr) node);
4068 if (tmp == NULL)
4069 node = node->children;
4070 else
4071 node = tmp;
4072
4073 if (node == NULL)
4074 return(0);
4075 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004076
4077 switch (node->type) {
4078 case XML_COMMENT_NODE:
4079 case XML_PI_NODE:
4080 case XML_CDATA_SECTION_NODE:
4081 case XML_TEXT_NODE:
4082 string = node->content;
4083 if (string == NULL)
4084 return(0);
4085 if (string[0] == 0)
4086 return(0);
4087 return(((unsigned int) string[0]) +
4088 (((unsigned int) string[1]) << 8));
4089 case XML_NAMESPACE_DECL:
4090 string = ((xmlNsPtr)node)->href;
4091 if (string == NULL)
4092 return(0);
4093 if (string[0] == 0)
4094 return(0);
4095 return(((unsigned int) string[0]) +
4096 (((unsigned int) string[1]) << 8));
4097 case XML_ATTRIBUTE_NODE:
4098 tmp = ((xmlAttrPtr) node)->children;
4099 break;
4100 case XML_ELEMENT_NODE:
4101 tmp = node->children;
4102 break;
4103 default:
4104 return(0);
4105 }
4106 while (tmp != NULL) {
4107 switch (tmp->type) {
4108 case XML_COMMENT_NODE:
4109 case XML_PI_NODE:
4110 case XML_CDATA_SECTION_NODE:
4111 case XML_TEXT_NODE:
4112 string = tmp->content;
4113 break;
4114 case XML_NAMESPACE_DECL:
4115 string = ((xmlNsPtr)tmp)->href;
4116 break;
4117 default:
4118 break;
4119 }
4120 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004121 if (len == 1) {
4122 return(ret + (((unsigned int) string[0]) << 8));
4123 }
4124 if (string[1] == 0) {
4125 len = 1;
4126 ret = (unsigned int) string[0];
4127 } else {
4128 return(((unsigned int) string[0]) +
4129 (((unsigned int) string[1]) << 8));
4130 }
4131 }
4132 /*
4133 * Skip to next node
4134 */
4135 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4136 if (tmp->children->type != XML_ENTITY_DECL) {
4137 tmp = tmp->children;
4138 continue;
4139 }
4140 }
4141 if (tmp == node)
4142 break;
4143
4144 if (tmp->next != NULL) {
4145 tmp = tmp->next;
4146 continue;
4147 }
4148
4149 do {
4150 tmp = tmp->parent;
4151 if (tmp == NULL)
4152 break;
4153 if (tmp == node) {
4154 tmp = NULL;
4155 break;
4156 }
4157 if (tmp->next != NULL) {
4158 tmp = tmp->next;
4159 break;
4160 }
4161 } while (tmp != NULL);
4162 }
4163 return(ret);
4164}
4165
4166/**
4167 * xmlXPathStringHash:
4168 * @string: a string
4169 *
4170 * Function computing the beginning of the string value of the node,
4171 * used to speed up comparisons
4172 *
4173 * Returns an int usable as a hash
4174 */
4175static unsigned int
4176xmlXPathStringHash(const xmlChar * string) {
4177 if (string == NULL)
4178 return((unsigned int) 0);
4179 if (string[0] == 0)
4180 return(0);
4181 return(((unsigned int) string[0]) +
4182 (((unsigned int) string[1]) << 8));
4183}
4184
4185/**
Owen Taylor3473f882001-02-23 17:55:21 +00004186 * xmlXPathCompareNodeSetFloat:
4187 * @ctxt: the XPath Parser context
4188 * @inf: less than (1) or greater than (0)
4189 * @strict: is the comparison strict
4190 * @arg: the node set
4191 * @f: the value
4192 *
4193 * Implement the compare operation between a nodeset and a number
4194 * @ns < @val (1, 1, ...
4195 * @ns <= @val (1, 0, ...
4196 * @ns > @val (0, 1, ...
4197 * @ns >= @val (0, 0, ...
4198 *
4199 * If one object to be compared is a node-set and the other is a number,
4200 * then the comparison will be true if and only if there is a node in the
4201 * node-set such that the result of performing the comparison on the number
4202 * to be compared and on the result of converting the string-value of that
4203 * node to a number using the number function is true.
4204 *
4205 * Returns 0 or 1 depending on the results of the test.
4206 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004207static int
Owen Taylor3473f882001-02-23 17:55:21 +00004208xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4209 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4210 int i, ret = 0;
4211 xmlNodeSetPtr ns;
4212 xmlChar *str2;
4213
4214 if ((f == NULL) || (arg == NULL) ||
4215 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4216 xmlXPathFreeObject(arg);
4217 xmlXPathFreeObject(f);
4218 return(0);
4219 }
4220 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004221 if (ns != NULL) {
4222 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004223 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004224 if (str2 != NULL) {
4225 valuePush(ctxt,
4226 xmlXPathNewString(str2));
4227 xmlFree(str2);
4228 xmlXPathNumberFunction(ctxt, 1);
4229 valuePush(ctxt, xmlXPathObjectCopy(f));
4230 ret = xmlXPathCompareValues(ctxt, inf, strict);
4231 if (ret)
4232 break;
4233 }
4234 }
Owen Taylor3473f882001-02-23 17:55:21 +00004235 }
4236 xmlXPathFreeObject(arg);
4237 xmlXPathFreeObject(f);
4238 return(ret);
4239}
4240
4241/**
4242 * xmlXPathCompareNodeSetString:
4243 * @ctxt: the XPath Parser context
4244 * @inf: less than (1) or greater than (0)
4245 * @strict: is the comparison strict
4246 * @arg: the node set
4247 * @s: the value
4248 *
4249 * Implement the compare operation between a nodeset and a string
4250 * @ns < @val (1, 1, ...
4251 * @ns <= @val (1, 0, ...
4252 * @ns > @val (0, 1, ...
4253 * @ns >= @val (0, 0, ...
4254 *
4255 * If one object to be compared is a node-set and the other is a string,
4256 * then the comparison will be true if and only if there is a node in
4257 * the node-set such that the result of performing the comparison on the
4258 * string-value of the node and the other string is true.
4259 *
4260 * Returns 0 or 1 depending on the results of the test.
4261 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004262static int
Owen Taylor3473f882001-02-23 17:55:21 +00004263xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4264 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4265 int i, ret = 0;
4266 xmlNodeSetPtr ns;
4267 xmlChar *str2;
4268
4269 if ((s == NULL) || (arg == NULL) ||
4270 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4271 xmlXPathFreeObject(arg);
4272 xmlXPathFreeObject(s);
4273 return(0);
4274 }
4275 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004276 if (ns != NULL) {
4277 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004278 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004279 if (str2 != NULL) {
4280 valuePush(ctxt,
4281 xmlXPathNewString(str2));
4282 xmlFree(str2);
4283 valuePush(ctxt, xmlXPathObjectCopy(s));
4284 ret = xmlXPathCompareValues(ctxt, inf, strict);
4285 if (ret)
4286 break;
4287 }
4288 }
Owen Taylor3473f882001-02-23 17:55:21 +00004289 }
4290 xmlXPathFreeObject(arg);
4291 xmlXPathFreeObject(s);
4292 return(ret);
4293}
4294
4295/**
4296 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004297 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004298 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004299 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004300 * @arg2: the second node set object
4301 *
4302 * Implement the compare operation on nodesets:
4303 *
4304 * If both objects to be compared are node-sets, then the comparison
4305 * will be true if and only if there is a node in the first node-set
4306 * and a node in the second node-set such that the result of performing
4307 * the comparison on the string-values of the two nodes is true.
4308 * ....
4309 * When neither object to be compared is a node-set and the operator
4310 * is <=, <, >= or >, then the objects are compared by converting both
4311 * objects to numbers and comparing the numbers according to IEEE 754.
4312 * ....
4313 * The number function converts its argument to a number as follows:
4314 * - a string that consists of optional whitespace followed by an
4315 * optional minus sign followed by a Number followed by whitespace
4316 * is converted to the IEEE 754 number that is nearest (according
4317 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4318 * represented by the string; any other string is converted to NaN
4319 *
4320 * Conclusion all nodes need to be converted first to their string value
4321 * and then the comparison must be done when possible
4322 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004323static int
4324xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004325 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4326 int i, j, init = 0;
4327 double val1;
4328 double *values2;
4329 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004330 xmlNodeSetPtr ns1;
4331 xmlNodeSetPtr ns2;
4332
4333 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004334 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4335 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004336 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004337 }
Owen Taylor3473f882001-02-23 17:55:21 +00004338 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004339 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4340 xmlXPathFreeObject(arg1);
4341 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004342 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004343 }
Owen Taylor3473f882001-02-23 17:55:21 +00004344
4345 ns1 = arg1->nodesetval;
4346 ns2 = arg2->nodesetval;
4347
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004348 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004349 xmlXPathFreeObject(arg1);
4350 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004351 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004352 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004353 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004354 xmlXPathFreeObject(arg1);
4355 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004356 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004357 }
Owen Taylor3473f882001-02-23 17:55:21 +00004358
4359 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4360 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004361 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004362 xmlXPathFreeObject(arg1);
4363 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004364 return(0);
4365 }
4366 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004367 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004368 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004369 continue;
4370 for (j = 0;j < ns2->nodeNr;j++) {
4371 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004372 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004373 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004374 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004375 continue;
4376 if (inf && strict)
4377 ret = (val1 < values2[j]);
4378 else if (inf && !strict)
4379 ret = (val1 <= values2[j]);
4380 else if (!inf && strict)
4381 ret = (val1 > values2[j]);
4382 else if (!inf && !strict)
4383 ret = (val1 >= values2[j]);
4384 if (ret)
4385 break;
4386 }
4387 if (ret)
4388 break;
4389 init = 1;
4390 }
4391 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004392 xmlXPathFreeObject(arg1);
4393 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004394 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004395}
4396
4397/**
4398 * xmlXPathCompareNodeSetValue:
4399 * @ctxt: the XPath Parser context
4400 * @inf: less than (1) or greater than (0)
4401 * @strict: is the comparison strict
4402 * @arg: the node set
4403 * @val: the value
4404 *
4405 * Implement the compare operation between a nodeset and a value
4406 * @ns < @val (1, 1, ...
4407 * @ns <= @val (1, 0, ...
4408 * @ns > @val (0, 1, ...
4409 * @ns >= @val (0, 0, ...
4410 *
4411 * If one object to be compared is a node-set and the other is a boolean,
4412 * then the comparison will be true if and only if the result of performing
4413 * the comparison on the boolean and on the result of converting
4414 * the node-set to a boolean using the boolean function is true.
4415 *
4416 * Returns 0 or 1 depending on the results of the test.
4417 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004418static int
Owen Taylor3473f882001-02-23 17:55:21 +00004419xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4420 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4421 if ((val == NULL) || (arg == NULL) ||
4422 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4423 return(0);
4424
4425 switch(val->type) {
4426 case XPATH_NUMBER:
4427 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4428 case XPATH_NODESET:
4429 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004430 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004431 case XPATH_STRING:
4432 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4433 case XPATH_BOOLEAN:
4434 valuePush(ctxt, arg);
4435 xmlXPathBooleanFunction(ctxt, 1);
4436 valuePush(ctxt, val);
4437 return(xmlXPathCompareValues(ctxt, inf, strict));
4438 default:
4439 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004440 }
4441 return(0);
4442}
4443
4444/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004445 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004446 * @arg: the nodeset object argument
4447 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004448 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004449 *
4450 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4451 * If one object to be compared is a node-set and the other is a string,
4452 * then the comparison will be true if and only if there is a node in
4453 * the node-set such that the result of performing the comparison on the
4454 * string-value of the node and the other string is true.
4455 *
4456 * Returns 0 or 1 depending on the results of the test.
4457 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004458static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004459xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004460{
Owen Taylor3473f882001-02-23 17:55:21 +00004461 int i;
4462 xmlNodeSetPtr ns;
4463 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004464 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004465
4466 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004467 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4468 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004469 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004470 /*
4471 * A NULL nodeset compared with a string is always false
4472 * (since there is no node equal, and no node not equal)
4473 */
4474 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004475 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004476 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004477 for (i = 0; i < ns->nodeNr; i++) {
4478 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4479 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4480 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4481 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004482 if (neq)
4483 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004484 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004485 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4486 if (neq)
4487 continue;
4488 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004489 } else if (neq) {
4490 if (str2 != NULL)
4491 xmlFree(str2);
4492 return (1);
4493 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004494 if (str2 != NULL)
4495 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004496 } else if (neq)
4497 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004498 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004499 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004500}
4501
4502/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004503 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004504 * @arg: the nodeset object argument
4505 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004506 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004507 *
4508 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4509 * If one object to be compared is a node-set and the other is a number,
4510 * then the comparison will be true if and only if there is a node in
4511 * the node-set such that the result of performing the comparison on the
4512 * number to be compared and on the result of converting the string-value
4513 * of that node to a number using the number function is true.
4514 *
4515 * Returns 0 or 1 depending on the results of the test.
4516 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004517static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004518xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4519 xmlXPathObjectPtr arg, double f, int neq) {
4520 int i, ret=0;
4521 xmlNodeSetPtr ns;
4522 xmlChar *str2;
4523 xmlXPathObjectPtr val;
4524 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004525
4526 if ((arg == NULL) ||
4527 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4528 return(0);
4529
William M. Brack0c022ad2002-07-12 00:56:01 +00004530 ns = arg->nodesetval;
4531 if (ns != NULL) {
4532 for (i=0;i<ns->nodeNr;i++) {
4533 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4534 if (str2 != NULL) {
4535 valuePush(ctxt, xmlXPathNewString(str2));
4536 xmlFree(str2);
4537 xmlXPathNumberFunction(ctxt, 1);
4538 val = valuePop(ctxt);
4539 v = val->floatval;
4540 xmlXPathFreeObject(val);
4541 if (!xmlXPathIsNaN(v)) {
4542 if ((!neq) && (v==f)) {
4543 ret = 1;
4544 break;
4545 } else if ((neq) && (v!=f)) {
4546 ret = 1;
4547 break;
4548 }
4549 }
4550 }
4551 }
4552 }
4553
4554 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004555}
4556
4557
4558/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004559 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004560 * @arg1: first nodeset object argument
4561 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004562 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004563 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004564 * Implement the equal / not equal operation on XPath nodesets:
4565 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004566 * If both objects to be compared are node-sets, then the comparison
4567 * will be true if and only if there is a node in the first node-set and
4568 * a node in the second node-set such that the result of performing the
4569 * comparison on the string-values of the two nodes is true.
4570 *
4571 * (needless to say, this is a costly operation)
4572 *
4573 * Returns 0 or 1 depending on the results of the test.
4574 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004575static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004576xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004577 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004578 unsigned int *hashs1;
4579 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004580 xmlChar **values1;
4581 xmlChar **values2;
4582 int ret = 0;
4583 xmlNodeSetPtr ns1;
4584 xmlNodeSetPtr ns2;
4585
4586 if ((arg1 == NULL) ||
4587 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4588 return(0);
4589 if ((arg2 == NULL) ||
4590 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4591 return(0);
4592
4593 ns1 = arg1->nodesetval;
4594 ns2 = arg2->nodesetval;
4595
Daniel Veillard911f49a2001-04-07 15:39:35 +00004596 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004597 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004598 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004599 return(0);
4600
4601 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004602 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004603 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004604 if (neq == 0)
4605 for (i = 0;i < ns1->nodeNr;i++)
4606 for (j = 0;j < ns2->nodeNr;j++)
4607 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4608 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004609
4610 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004611 if (values1 == NULL) {
4612 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004613 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004614 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004615 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4616 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004617 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004618 xmlFree(values1);
4619 return(0);
4620 }
Owen Taylor3473f882001-02-23 17:55:21 +00004621 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4622 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4623 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004624 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004625 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004626 xmlFree(values1);
4627 return(0);
4628 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004629 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4630 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004631 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004632 xmlFree(hashs1);
4633 xmlFree(values1);
4634 xmlFree(values2);
4635 return(0);
4636 }
Owen Taylor3473f882001-02-23 17:55:21 +00004637 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4638 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004639 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004640 for (j = 0;j < ns2->nodeNr;j++) {
4641 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004642 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004643 if (hashs1[i] != hashs2[j]) {
4644 if (neq) {
4645 ret = 1;
4646 break;
4647 }
4648 }
4649 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004650 if (values1[i] == NULL)
4651 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4652 if (values2[j] == NULL)
4653 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004654 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004655 if (ret)
4656 break;
4657 }
Owen Taylor3473f882001-02-23 17:55:21 +00004658 }
4659 if (ret)
4660 break;
4661 }
4662 for (i = 0;i < ns1->nodeNr;i++)
4663 if (values1[i] != NULL)
4664 xmlFree(values1[i]);
4665 for (j = 0;j < ns2->nodeNr;j++)
4666 if (values2[j] != NULL)
4667 xmlFree(values2[j]);
4668 xmlFree(values1);
4669 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004670 xmlFree(hashs1);
4671 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004672 return(ret);
4673}
4674
William M. Brack0c022ad2002-07-12 00:56:01 +00004675static int
4676xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4677 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004678 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004679 /*
4680 *At this point we are assured neither arg1 nor arg2
4681 *is a nodeset, so we can just pick the appropriate routine.
4682 */
Owen Taylor3473f882001-02-23 17:55:21 +00004683 switch (arg1->type) {
4684 case XPATH_UNDEFINED:
4685#ifdef DEBUG_EXPR
4686 xmlGenericError(xmlGenericErrorContext,
4687 "Equal: undefined\n");
4688#endif
4689 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004690 case XPATH_BOOLEAN:
4691 switch (arg2->type) {
4692 case XPATH_UNDEFINED:
4693#ifdef DEBUG_EXPR
4694 xmlGenericError(xmlGenericErrorContext,
4695 "Equal: undefined\n");
4696#endif
4697 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004698 case XPATH_BOOLEAN:
4699#ifdef DEBUG_EXPR
4700 xmlGenericError(xmlGenericErrorContext,
4701 "Equal: %d boolean %d \n",
4702 arg1->boolval, arg2->boolval);
4703#endif
4704 ret = (arg1->boolval == arg2->boolval);
4705 break;
4706 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004707 ret = (arg1->boolval ==
4708 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004709 break;
4710 case XPATH_STRING:
4711 if ((arg2->stringval == NULL) ||
4712 (arg2->stringval[0] == 0)) ret = 0;
4713 else
4714 ret = 1;
4715 ret = (arg1->boolval == ret);
4716 break;
4717 case XPATH_USERS:
4718 case XPATH_POINT:
4719 case XPATH_RANGE:
4720 case XPATH_LOCATIONSET:
4721 TODO
4722 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004723 case XPATH_NODESET:
4724 case XPATH_XSLT_TREE:
4725 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004726 }
4727 break;
4728 case XPATH_NUMBER:
4729 switch (arg2->type) {
4730 case XPATH_UNDEFINED:
4731#ifdef DEBUG_EXPR
4732 xmlGenericError(xmlGenericErrorContext,
4733 "Equal: undefined\n");
4734#endif
4735 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004736 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004737 ret = (arg2->boolval==
4738 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004739 break;
4740 case XPATH_STRING:
4741 valuePush(ctxt, arg2);
4742 xmlXPathNumberFunction(ctxt, 1);
4743 arg2 = valuePop(ctxt);
4744 /* no break on purpose */
4745 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004746 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004747 if (xmlXPathIsNaN(arg1->floatval) ||
4748 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004749 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004750 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4751 if (xmlXPathIsInf(arg2->floatval) == 1)
4752 ret = 1;
4753 else
4754 ret = 0;
4755 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4756 if (xmlXPathIsInf(arg2->floatval) == -1)
4757 ret = 1;
4758 else
4759 ret = 0;
4760 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4761 if (xmlXPathIsInf(arg1->floatval) == 1)
4762 ret = 1;
4763 else
4764 ret = 0;
4765 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4766 if (xmlXPathIsInf(arg1->floatval) == -1)
4767 ret = 1;
4768 else
4769 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004770 } else {
4771 ret = (arg1->floatval == arg2->floatval);
4772 }
Owen Taylor3473f882001-02-23 17:55:21 +00004773 break;
4774 case XPATH_USERS:
4775 case XPATH_POINT:
4776 case XPATH_RANGE:
4777 case XPATH_LOCATIONSET:
4778 TODO
4779 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004780 case XPATH_NODESET:
4781 case XPATH_XSLT_TREE:
4782 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004783 }
4784 break;
4785 case XPATH_STRING:
4786 switch (arg2->type) {
4787 case XPATH_UNDEFINED:
4788#ifdef DEBUG_EXPR
4789 xmlGenericError(xmlGenericErrorContext,
4790 "Equal: undefined\n");
4791#endif
4792 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004793 case XPATH_BOOLEAN:
4794 if ((arg1->stringval == NULL) ||
4795 (arg1->stringval[0] == 0)) ret = 0;
4796 else
4797 ret = 1;
4798 ret = (arg2->boolval == ret);
4799 break;
4800 case XPATH_STRING:
4801 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4802 break;
4803 case XPATH_NUMBER:
4804 valuePush(ctxt, arg1);
4805 xmlXPathNumberFunction(ctxt, 1);
4806 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004807 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004808 if (xmlXPathIsNaN(arg1->floatval) ||
4809 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004810 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004811 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4812 if (xmlXPathIsInf(arg2->floatval) == 1)
4813 ret = 1;
4814 else
4815 ret = 0;
4816 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4817 if (xmlXPathIsInf(arg2->floatval) == -1)
4818 ret = 1;
4819 else
4820 ret = 0;
4821 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4822 if (xmlXPathIsInf(arg1->floatval) == 1)
4823 ret = 1;
4824 else
4825 ret = 0;
4826 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4827 if (xmlXPathIsInf(arg1->floatval) == -1)
4828 ret = 1;
4829 else
4830 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004831 } else {
4832 ret = (arg1->floatval == arg2->floatval);
4833 }
Owen Taylor3473f882001-02-23 17:55:21 +00004834 break;
4835 case XPATH_USERS:
4836 case XPATH_POINT:
4837 case XPATH_RANGE:
4838 case XPATH_LOCATIONSET:
4839 TODO
4840 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004841 case XPATH_NODESET:
4842 case XPATH_XSLT_TREE:
4843 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004844 }
4845 break;
4846 case XPATH_USERS:
4847 case XPATH_POINT:
4848 case XPATH_RANGE:
4849 case XPATH_LOCATIONSET:
4850 TODO
4851 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004852 case XPATH_NODESET:
4853 case XPATH_XSLT_TREE:
4854 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004855 }
4856 xmlXPathFreeObject(arg1);
4857 xmlXPathFreeObject(arg2);
4858 return(ret);
4859}
4860
William M. Brack0c022ad2002-07-12 00:56:01 +00004861/**
4862 * xmlXPathEqualValues:
4863 * @ctxt: the XPath Parser context
4864 *
4865 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4866 *
4867 * Returns 0 or 1 depending on the results of the test.
4868 */
4869int
4870xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4871 xmlXPathObjectPtr arg1, arg2, argtmp;
4872 int ret = 0;
4873
4874 arg2 = valuePop(ctxt);
4875 arg1 = valuePop(ctxt);
4876 if ((arg1 == NULL) || (arg2 == NULL)) {
4877 if (arg1 != NULL)
4878 xmlXPathFreeObject(arg1);
4879 else
4880 xmlXPathFreeObject(arg2);
4881 XP_ERROR0(XPATH_INVALID_OPERAND);
4882 }
4883
4884 if (arg1 == arg2) {
4885#ifdef DEBUG_EXPR
4886 xmlGenericError(xmlGenericErrorContext,
4887 "Equal: by pointer\n");
4888#endif
4889 return(1);
4890 }
4891
4892 /*
4893 *If either argument is a nodeset, it's a 'special case'
4894 */
4895 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4896 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4897 /*
4898 *Hack it to assure arg1 is the nodeset
4899 */
4900 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4901 argtmp = arg2;
4902 arg2 = arg1;
4903 arg1 = argtmp;
4904 }
4905 switch (arg2->type) {
4906 case XPATH_UNDEFINED:
4907#ifdef DEBUG_EXPR
4908 xmlGenericError(xmlGenericErrorContext,
4909 "Equal: undefined\n");
4910#endif
4911 break;
4912 case XPATH_NODESET:
4913 case XPATH_XSLT_TREE:
4914 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4915 break;
4916 case XPATH_BOOLEAN:
4917 if ((arg1->nodesetval == NULL) ||
4918 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4919 else
4920 ret = 1;
4921 ret = (ret == arg2->boolval);
4922 break;
4923 case XPATH_NUMBER:
4924 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4925 break;
4926 case XPATH_STRING:
4927 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4928 break;
4929 case XPATH_USERS:
4930 case XPATH_POINT:
4931 case XPATH_RANGE:
4932 case XPATH_LOCATIONSET:
4933 TODO
4934 break;
4935 }
4936 xmlXPathFreeObject(arg1);
4937 xmlXPathFreeObject(arg2);
4938 return(ret);
4939 }
4940
4941 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4942}
4943
4944/**
4945 * xmlXPathNotEqualValues:
4946 * @ctxt: the XPath Parser context
4947 *
4948 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4949 *
4950 * Returns 0 or 1 depending on the results of the test.
4951 */
4952int
4953xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4954 xmlXPathObjectPtr arg1, arg2, argtmp;
4955 int ret = 0;
4956
4957 arg2 = valuePop(ctxt);
4958 arg1 = valuePop(ctxt);
4959 if ((arg1 == NULL) || (arg2 == NULL)) {
4960 if (arg1 != NULL)
4961 xmlXPathFreeObject(arg1);
4962 else
4963 xmlXPathFreeObject(arg2);
4964 XP_ERROR0(XPATH_INVALID_OPERAND);
4965 }
4966
4967 if (arg1 == arg2) {
4968#ifdef DEBUG_EXPR
4969 xmlGenericError(xmlGenericErrorContext,
4970 "NotEqual: by pointer\n");
4971#endif
4972 return(0);
4973 }
4974
4975 /*
4976 *If either argument is a nodeset, it's a 'special case'
4977 */
4978 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4979 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4980 /*
4981 *Hack it to assure arg1 is the nodeset
4982 */
4983 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4984 argtmp = arg2;
4985 arg2 = arg1;
4986 arg1 = argtmp;
4987 }
4988 switch (arg2->type) {
4989 case XPATH_UNDEFINED:
4990#ifdef DEBUG_EXPR
4991 xmlGenericError(xmlGenericErrorContext,
4992 "NotEqual: undefined\n");
4993#endif
4994 break;
4995 case XPATH_NODESET:
4996 case XPATH_XSLT_TREE:
4997 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4998 break;
4999 case XPATH_BOOLEAN:
5000 if ((arg1->nodesetval == NULL) ||
5001 (arg1->nodesetval->nodeNr == 0)) ret = 0;
5002 else
5003 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00005004 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00005005 break;
5006 case XPATH_NUMBER:
5007 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5008 break;
5009 case XPATH_STRING:
5010 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
5011 break;
5012 case XPATH_USERS:
5013 case XPATH_POINT:
5014 case XPATH_RANGE:
5015 case XPATH_LOCATIONSET:
5016 TODO
5017 break;
5018 }
5019 xmlXPathFreeObject(arg1);
5020 xmlXPathFreeObject(arg2);
5021 return(ret);
5022 }
5023
5024 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5025}
Owen Taylor3473f882001-02-23 17:55:21 +00005026
5027/**
5028 * xmlXPathCompareValues:
5029 * @ctxt: the XPath Parser context
5030 * @inf: less than (1) or greater than (0)
5031 * @strict: is the comparison strict
5032 *
5033 * Implement the compare operation on XPath objects:
5034 * @arg1 < @arg2 (1, 1, ...
5035 * @arg1 <= @arg2 (1, 0, ...
5036 * @arg1 > @arg2 (0, 1, ...
5037 * @arg1 >= @arg2 (0, 0, ...
5038 *
5039 * When neither object to be compared is a node-set and the operator is
5040 * <=, <, >=, >, then the objects are compared by converted both objects
5041 * to numbers and comparing the numbers according to IEEE 754. The <
5042 * comparison will be true if and only if the first number is less than the
5043 * second number. The <= comparison will be true if and only if the first
5044 * number is less than or equal to the second number. The > comparison
5045 * will be true if and only if the first number is greater than the second
5046 * number. The >= comparison will be true if and only if the first number
5047 * is greater than or equal to the second number.
5048 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005049 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005050 */
5051int
5052xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005053 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005054 xmlXPathObjectPtr arg1, arg2;
5055
William M. Brack0c022ad2002-07-12 00:56:01 +00005056 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005057 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005058 if ((arg1 == NULL) || (arg2 == NULL)) {
5059 if (arg1 != NULL)
5060 xmlXPathFreeObject(arg1);
5061 else
5062 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005063 XP_ERROR0(XPATH_INVALID_OPERAND);
5064 }
5065
William M. Brack0c022ad2002-07-12 00:56:01 +00005066 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5067 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5068 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5069 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005070 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005071 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005072 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005073 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5074 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005075 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005076 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5077 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005078 }
5079 }
5080 return(ret);
5081 }
5082
5083 if (arg1->type != XPATH_NUMBER) {
5084 valuePush(ctxt, arg1);
5085 xmlXPathNumberFunction(ctxt, 1);
5086 arg1 = valuePop(ctxt);
5087 }
5088 if (arg1->type != XPATH_NUMBER) {
5089 xmlXPathFreeObject(arg1);
5090 xmlXPathFreeObject(arg2);
5091 XP_ERROR0(XPATH_INVALID_OPERAND);
5092 }
5093 if (arg2->type != XPATH_NUMBER) {
5094 valuePush(ctxt, arg2);
5095 xmlXPathNumberFunction(ctxt, 1);
5096 arg2 = valuePop(ctxt);
5097 }
5098 if (arg2->type != XPATH_NUMBER) {
5099 xmlXPathFreeObject(arg1);
5100 xmlXPathFreeObject(arg2);
5101 XP_ERROR0(XPATH_INVALID_OPERAND);
5102 }
5103 /*
5104 * Add tests for infinity and nan
5105 * => feedback on 3.4 for Inf and NaN
5106 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005107 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005108 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005109 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005110 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005111 arg1i=xmlXPathIsInf(arg1->floatval);
5112 arg2i=xmlXPathIsInf(arg2->floatval);
5113 if (inf && strict) {
5114 if ((arg1i == -1 && arg2i != -1) ||
5115 (arg2i == 1 && arg1i != 1)) {
5116 ret = 1;
5117 } else if (arg1i == 0 && arg2i == 0) {
5118 ret = (arg1->floatval < arg2->floatval);
5119 } else {
5120 ret = 0;
5121 }
5122 }
5123 else if (inf && !strict) {
5124 if (arg1i == -1 || arg2i == 1) {
5125 ret = 1;
5126 } else if (arg1i == 0 && arg2i == 0) {
5127 ret = (arg1->floatval <= arg2->floatval);
5128 } else {
5129 ret = 0;
5130 }
5131 }
5132 else if (!inf && strict) {
5133 if ((arg1i == 1 && arg2i != 1) ||
5134 (arg2i == -1 && arg1i != -1)) {
5135 ret = 1;
5136 } else if (arg1i == 0 && arg2i == 0) {
5137 ret = (arg1->floatval > arg2->floatval);
5138 } else {
5139 ret = 0;
5140 }
5141 }
5142 else if (!inf && !strict) {
5143 if (arg1i == 1 || arg2i == -1) {
5144 ret = 1;
5145 } else if (arg1i == 0 && arg2i == 0) {
5146 ret = (arg1->floatval >= arg2->floatval);
5147 } else {
5148 ret = 0;
5149 }
5150 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005151 }
Owen Taylor3473f882001-02-23 17:55:21 +00005152 xmlXPathFreeObject(arg1);
5153 xmlXPathFreeObject(arg2);
5154 return(ret);
5155}
5156
5157/**
5158 * xmlXPathValueFlipSign:
5159 * @ctxt: the XPath Parser context
5160 *
5161 * Implement the unary - operation on an XPath object
5162 * The numeric operators convert their operands to numbers as if
5163 * by calling the number function.
5164 */
5165void
5166xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005167 CAST_TO_NUMBER;
5168 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005169 if (xmlXPathIsNaN(ctxt->value->floatval))
5170 ctxt->value->floatval=xmlXPathNAN;
5171 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5172 ctxt->value->floatval=xmlXPathNINF;
5173 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5174 ctxt->value->floatval=xmlXPathPINF;
5175 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005176 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5177 ctxt->value->floatval = xmlXPathNZERO;
5178 else
5179 ctxt->value->floatval = 0;
5180 }
5181 else
5182 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005183}
5184
5185/**
5186 * xmlXPathAddValues:
5187 * @ctxt: the XPath Parser context
5188 *
5189 * Implement the add operation on XPath objects:
5190 * The numeric operators convert their operands to numbers as if
5191 * by calling the number function.
5192 */
5193void
5194xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5195 xmlXPathObjectPtr arg;
5196 double val;
5197
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005198 arg = valuePop(ctxt);
5199 if (arg == NULL)
5200 XP_ERROR(XPATH_INVALID_OPERAND);
5201 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005202 xmlXPathFreeObject(arg);
5203
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005204 CAST_TO_NUMBER;
5205 CHECK_TYPE(XPATH_NUMBER);
5206 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005207}
5208
5209/**
5210 * xmlXPathSubValues:
5211 * @ctxt: the XPath Parser context
5212 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005213 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005214 * The numeric operators convert their operands to numbers as if
5215 * by calling the number function.
5216 */
5217void
5218xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5219 xmlXPathObjectPtr arg;
5220 double val;
5221
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005222 arg = valuePop(ctxt);
5223 if (arg == NULL)
5224 XP_ERROR(XPATH_INVALID_OPERAND);
5225 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005226 xmlXPathFreeObject(arg);
5227
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005228 CAST_TO_NUMBER;
5229 CHECK_TYPE(XPATH_NUMBER);
5230 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005231}
5232
5233/**
5234 * xmlXPathMultValues:
5235 * @ctxt: the XPath Parser context
5236 *
5237 * Implement the multiply operation on XPath objects:
5238 * The numeric operators convert their operands to numbers as if
5239 * by calling the number function.
5240 */
5241void
5242xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5243 xmlXPathObjectPtr arg;
5244 double val;
5245
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005246 arg = valuePop(ctxt);
5247 if (arg == NULL)
5248 XP_ERROR(XPATH_INVALID_OPERAND);
5249 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005250 xmlXPathFreeObject(arg);
5251
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005252 CAST_TO_NUMBER;
5253 CHECK_TYPE(XPATH_NUMBER);
5254 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005255}
5256
5257/**
5258 * xmlXPathDivValues:
5259 * @ctxt: the XPath Parser context
5260 *
5261 * Implement the div operation on XPath objects @arg1 / @arg2:
5262 * The numeric operators convert their operands to numbers as if
5263 * by calling the number function.
5264 */
5265void
5266xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5267 xmlXPathObjectPtr arg;
5268 double val;
5269
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005270 arg = valuePop(ctxt);
5271 if (arg == NULL)
5272 XP_ERROR(XPATH_INVALID_OPERAND);
5273 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005274 xmlXPathFreeObject(arg);
5275
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005276 CAST_TO_NUMBER;
5277 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005278 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5279 ctxt->value->floatval = xmlXPathNAN;
5280 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005281 if (ctxt->value->floatval == 0)
5282 ctxt->value->floatval = xmlXPathNAN;
5283 else if (ctxt->value->floatval > 0)
5284 ctxt->value->floatval = xmlXPathNINF;
5285 else if (ctxt->value->floatval < 0)
5286 ctxt->value->floatval = xmlXPathPINF;
5287 }
5288 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005289 if (ctxt->value->floatval == 0)
5290 ctxt->value->floatval = xmlXPathNAN;
5291 else if (ctxt->value->floatval > 0)
5292 ctxt->value->floatval = xmlXPathPINF;
5293 else if (ctxt->value->floatval < 0)
5294 ctxt->value->floatval = xmlXPathNINF;
5295 } else
5296 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005297}
5298
5299/**
5300 * xmlXPathModValues:
5301 * @ctxt: the XPath Parser context
5302 *
5303 * Implement the mod operation on XPath objects: @arg1 / @arg2
5304 * The numeric operators convert their operands to numbers as if
5305 * by calling the number function.
5306 */
5307void
5308xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5309 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005310 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005311
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005312 arg = valuePop(ctxt);
5313 if (arg == NULL)
5314 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005315 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005316 xmlXPathFreeObject(arg);
5317
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005318 CAST_TO_NUMBER;
5319 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005320 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005321 if (arg2 == 0)
5322 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005323 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005324 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005325 }
Owen Taylor3473f882001-02-23 17:55:21 +00005326}
5327
5328/************************************************************************
5329 * *
5330 * The traversal functions *
5331 * *
5332 ************************************************************************/
5333
Owen Taylor3473f882001-02-23 17:55:21 +00005334/*
5335 * A traversal function enumerates nodes along an axis.
5336 * Initially it must be called with NULL, and it indicates
5337 * termination on the axis by returning NULL.
5338 */
5339typedef xmlNodePtr (*xmlXPathTraversalFunction)
5340 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5341
5342/**
5343 * xmlXPathNextSelf:
5344 * @ctxt: the XPath Parser context
5345 * @cur: the current node in the traversal
5346 *
5347 * Traversal function for the "self" direction
5348 * The self axis contains just the context node itself
5349 *
5350 * Returns the next element following that axis
5351 */
5352xmlNodePtr
5353xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5354 if (cur == NULL)
5355 return(ctxt->context->node);
5356 return(NULL);
5357}
5358
5359/**
5360 * xmlXPathNextChild:
5361 * @ctxt: the XPath Parser context
5362 * @cur: the current node in the traversal
5363 *
5364 * Traversal function for the "child" direction
5365 * The child axis contains the children of the context node in document order.
5366 *
5367 * Returns the next element following that axis
5368 */
5369xmlNodePtr
5370xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5371 if (cur == NULL) {
5372 if (ctxt->context->node == NULL) return(NULL);
5373 switch (ctxt->context->node->type) {
5374 case XML_ELEMENT_NODE:
5375 case XML_TEXT_NODE:
5376 case XML_CDATA_SECTION_NODE:
5377 case XML_ENTITY_REF_NODE:
5378 case XML_ENTITY_NODE:
5379 case XML_PI_NODE:
5380 case XML_COMMENT_NODE:
5381 case XML_NOTATION_NODE:
5382 case XML_DTD_NODE:
5383 return(ctxt->context->node->children);
5384 case XML_DOCUMENT_NODE:
5385 case XML_DOCUMENT_TYPE_NODE:
5386 case XML_DOCUMENT_FRAG_NODE:
5387 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005388#ifdef LIBXML_DOCB_ENABLED
5389 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005390#endif
5391 return(((xmlDocPtr) ctxt->context->node)->children);
5392 case XML_ELEMENT_DECL:
5393 case XML_ATTRIBUTE_DECL:
5394 case XML_ENTITY_DECL:
5395 case XML_ATTRIBUTE_NODE:
5396 case XML_NAMESPACE_DECL:
5397 case XML_XINCLUDE_START:
5398 case XML_XINCLUDE_END:
5399 return(NULL);
5400 }
5401 return(NULL);
5402 }
5403 if ((cur->type == XML_DOCUMENT_NODE) ||
5404 (cur->type == XML_HTML_DOCUMENT_NODE))
5405 return(NULL);
5406 return(cur->next);
5407}
5408
5409/**
5410 * xmlXPathNextDescendant:
5411 * @ctxt: the XPath Parser context
5412 * @cur: the current node in the traversal
5413 *
5414 * Traversal function for the "descendant" direction
5415 * the descendant axis contains the descendants of the context node in document
5416 * order; a descendant is a child or a child of a child and so on.
5417 *
5418 * Returns the next element following that axis
5419 */
5420xmlNodePtr
5421xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5422 if (cur == NULL) {
5423 if (ctxt->context->node == NULL)
5424 return(NULL);
5425 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5426 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5427 return(NULL);
5428
5429 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5430 return(ctxt->context->doc->children);
5431 return(ctxt->context->node->children);
5432 }
5433
Daniel Veillard567e1b42001-08-01 15:53:47 +00005434 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005435 /*
5436 * Do not descend on entities declarations
5437 */
5438 if (cur->children->type != XML_ENTITY_DECL) {
5439 cur = cur->children;
5440 /*
5441 * Skip DTDs
5442 */
5443 if (cur->type != XML_DTD_NODE)
5444 return(cur);
5445 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005446 }
5447
5448 if (cur == ctxt->context->node) return(NULL);
5449
Daniel Veillard68e9e742002-11-16 15:35:11 +00005450 while (cur->next != NULL) {
5451 cur = cur->next;
5452 if ((cur->type != XML_ENTITY_DECL) &&
5453 (cur->type != XML_DTD_NODE))
5454 return(cur);
5455 }
Owen Taylor3473f882001-02-23 17:55:21 +00005456
5457 do {
5458 cur = cur->parent;
5459 if (cur == NULL) return(NULL);
5460 if (cur == ctxt->context->node) return(NULL);
5461 if (cur->next != NULL) {
5462 cur = cur->next;
5463 return(cur);
5464 }
5465 } while (cur != NULL);
5466 return(cur);
5467}
5468
5469/**
5470 * xmlXPathNextDescendantOrSelf:
5471 * @ctxt: the XPath Parser context
5472 * @cur: the current node in the traversal
5473 *
5474 * Traversal function for the "descendant-or-self" direction
5475 * the descendant-or-self axis contains the context node and the descendants
5476 * of the context node in document order; thus the context node is the first
5477 * node on the axis, and the first child of the context node is the second node
5478 * on the axis
5479 *
5480 * Returns the next element following that axis
5481 */
5482xmlNodePtr
5483xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5484 if (cur == NULL) {
5485 if (ctxt->context->node == NULL)
5486 return(NULL);
5487 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5488 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5489 return(NULL);
5490 return(ctxt->context->node);
5491 }
5492
5493 return(xmlXPathNextDescendant(ctxt, cur));
5494}
5495
5496/**
5497 * xmlXPathNextParent:
5498 * @ctxt: the XPath Parser context
5499 * @cur: the current node in the traversal
5500 *
5501 * Traversal function for the "parent" direction
5502 * The parent axis contains the parent of the context node, if there is one.
5503 *
5504 * Returns the next element following that axis
5505 */
5506xmlNodePtr
5507xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5508 /*
5509 * the parent of an attribute or namespace node is the element
5510 * to which the attribute or namespace node is attached
5511 * Namespace handling !!!
5512 */
5513 if (cur == NULL) {
5514 if (ctxt->context->node == NULL) return(NULL);
5515 switch (ctxt->context->node->type) {
5516 case XML_ELEMENT_NODE:
5517 case XML_TEXT_NODE:
5518 case XML_CDATA_SECTION_NODE:
5519 case XML_ENTITY_REF_NODE:
5520 case XML_ENTITY_NODE:
5521 case XML_PI_NODE:
5522 case XML_COMMENT_NODE:
5523 case XML_NOTATION_NODE:
5524 case XML_DTD_NODE:
5525 case XML_ELEMENT_DECL:
5526 case XML_ATTRIBUTE_DECL:
5527 case XML_XINCLUDE_START:
5528 case XML_XINCLUDE_END:
5529 case XML_ENTITY_DECL:
5530 if (ctxt->context->node->parent == NULL)
5531 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005532 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005533 ((ctxt->context->node->parent->name[0] == ' ') ||
5534 (xmlStrEqual(ctxt->context->node->parent->name,
5535 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005536 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005537 return(ctxt->context->node->parent);
5538 case XML_ATTRIBUTE_NODE: {
5539 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5540
5541 return(att->parent);
5542 }
5543 case XML_DOCUMENT_NODE:
5544 case XML_DOCUMENT_TYPE_NODE:
5545 case XML_DOCUMENT_FRAG_NODE:
5546 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005547#ifdef LIBXML_DOCB_ENABLED
5548 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005549#endif
5550 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005551 case XML_NAMESPACE_DECL: {
5552 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5553
5554 if ((ns->next != NULL) &&
5555 (ns->next->type != XML_NAMESPACE_DECL))
5556 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005557 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005558 }
Owen Taylor3473f882001-02-23 17:55:21 +00005559 }
5560 }
5561 return(NULL);
5562}
5563
5564/**
5565 * xmlXPathNextAncestor:
5566 * @ctxt: the XPath Parser context
5567 * @cur: the current node in the traversal
5568 *
5569 * Traversal function for the "ancestor" direction
5570 * the ancestor axis contains the ancestors of the context node; the ancestors
5571 * of the context node consist of the parent of context node and the parent's
5572 * parent and so on; the nodes are ordered in reverse document order; thus the
5573 * parent is the first node on the axis, and the parent's parent is the second
5574 * node on the axis
5575 *
5576 * Returns the next element following that axis
5577 */
5578xmlNodePtr
5579xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5580 /*
5581 * the parent of an attribute or namespace node is the element
5582 * to which the attribute or namespace node is attached
5583 * !!!!!!!!!!!!!
5584 */
5585 if (cur == NULL) {
5586 if (ctxt->context->node == NULL) return(NULL);
5587 switch (ctxt->context->node->type) {
5588 case XML_ELEMENT_NODE:
5589 case XML_TEXT_NODE:
5590 case XML_CDATA_SECTION_NODE:
5591 case XML_ENTITY_REF_NODE:
5592 case XML_ENTITY_NODE:
5593 case XML_PI_NODE:
5594 case XML_COMMENT_NODE:
5595 case XML_DTD_NODE:
5596 case XML_ELEMENT_DECL:
5597 case XML_ATTRIBUTE_DECL:
5598 case XML_ENTITY_DECL:
5599 case XML_NOTATION_NODE:
5600 case XML_XINCLUDE_START:
5601 case XML_XINCLUDE_END:
5602 if (ctxt->context->node->parent == NULL)
5603 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005604 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005605 ((ctxt->context->node->parent->name[0] == ' ') ||
5606 (xmlStrEqual(ctxt->context->node->parent->name,
5607 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005608 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005609 return(ctxt->context->node->parent);
5610 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005611 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005612
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005613 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005614 }
5615 case XML_DOCUMENT_NODE:
5616 case XML_DOCUMENT_TYPE_NODE:
5617 case XML_DOCUMENT_FRAG_NODE:
5618 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005619#ifdef LIBXML_DOCB_ENABLED
5620 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005621#endif
5622 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005623 case XML_NAMESPACE_DECL: {
5624 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5625
5626 if ((ns->next != NULL) &&
5627 (ns->next->type != XML_NAMESPACE_DECL))
5628 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005629 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005630 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005631 }
Owen Taylor3473f882001-02-23 17:55:21 +00005632 }
5633 return(NULL);
5634 }
5635 if (cur == ctxt->context->doc->children)
5636 return((xmlNodePtr) ctxt->context->doc);
5637 if (cur == (xmlNodePtr) ctxt->context->doc)
5638 return(NULL);
5639 switch (cur->type) {
5640 case XML_ELEMENT_NODE:
5641 case XML_TEXT_NODE:
5642 case XML_CDATA_SECTION_NODE:
5643 case XML_ENTITY_REF_NODE:
5644 case XML_ENTITY_NODE:
5645 case XML_PI_NODE:
5646 case XML_COMMENT_NODE:
5647 case XML_NOTATION_NODE:
5648 case XML_DTD_NODE:
5649 case XML_ELEMENT_DECL:
5650 case XML_ATTRIBUTE_DECL:
5651 case XML_ENTITY_DECL:
5652 case XML_XINCLUDE_START:
5653 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005654 if (cur->parent == NULL)
5655 return(NULL);
5656 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005657 ((cur->parent->name[0] == ' ') ||
5658 (xmlStrEqual(cur->parent->name,
5659 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005660 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005661 return(cur->parent);
5662 case XML_ATTRIBUTE_NODE: {
5663 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5664
5665 return(att->parent);
5666 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005667 case XML_NAMESPACE_DECL: {
5668 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5669
5670 if ((ns->next != NULL) &&
5671 (ns->next->type != XML_NAMESPACE_DECL))
5672 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005673 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005674 return(NULL);
5675 }
Owen Taylor3473f882001-02-23 17:55:21 +00005676 case XML_DOCUMENT_NODE:
5677 case XML_DOCUMENT_TYPE_NODE:
5678 case XML_DOCUMENT_FRAG_NODE:
5679 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005680#ifdef LIBXML_DOCB_ENABLED
5681 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005682#endif
5683 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005684 }
5685 return(NULL);
5686}
5687
5688/**
5689 * xmlXPathNextAncestorOrSelf:
5690 * @ctxt: the XPath Parser context
5691 * @cur: the current node in the traversal
5692 *
5693 * Traversal function for the "ancestor-or-self" direction
5694 * he ancestor-or-self axis contains the context node and ancestors of
5695 * the context node in reverse document order; thus the context node is
5696 * the first node on the axis, and the context node's parent the second;
5697 * parent here is defined the same as with the parent axis.
5698 *
5699 * Returns the next element following that axis
5700 */
5701xmlNodePtr
5702xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5703 if (cur == NULL)
5704 return(ctxt->context->node);
5705 return(xmlXPathNextAncestor(ctxt, cur));
5706}
5707
5708/**
5709 * xmlXPathNextFollowingSibling:
5710 * @ctxt: the XPath Parser context
5711 * @cur: the current node in the traversal
5712 *
5713 * Traversal function for the "following-sibling" direction
5714 * The following-sibling axis contains the following siblings of the context
5715 * node in document order.
5716 *
5717 * Returns the next element following that axis
5718 */
5719xmlNodePtr
5720xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5721 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5722 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5723 return(NULL);
5724 if (cur == (xmlNodePtr) ctxt->context->doc)
5725 return(NULL);
5726 if (cur == NULL)
5727 return(ctxt->context->node->next);
5728 return(cur->next);
5729}
5730
5731/**
5732 * xmlXPathNextPrecedingSibling:
5733 * @ctxt: the XPath Parser context
5734 * @cur: the current node in the traversal
5735 *
5736 * Traversal function for the "preceding-sibling" direction
5737 * The preceding-sibling axis contains the preceding siblings of the context
5738 * node in reverse document order; the first preceding sibling is first on the
5739 * axis; the sibling preceding that node is the second on the axis and so on.
5740 *
5741 * Returns the next element following that axis
5742 */
5743xmlNodePtr
5744xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5745 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5746 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5747 return(NULL);
5748 if (cur == (xmlNodePtr) ctxt->context->doc)
5749 return(NULL);
5750 if (cur == NULL)
5751 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005752 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5753 cur = cur->prev;
5754 if (cur == NULL)
5755 return(ctxt->context->node->prev);
5756 }
Owen Taylor3473f882001-02-23 17:55:21 +00005757 return(cur->prev);
5758}
5759
5760/**
5761 * xmlXPathNextFollowing:
5762 * @ctxt: the XPath Parser context
5763 * @cur: the current node in the traversal
5764 *
5765 * Traversal function for the "following" direction
5766 * The following axis contains all nodes in the same document as the context
5767 * node that are after the context node in document order, excluding any
5768 * descendants and excluding attribute nodes and namespace nodes; the nodes
5769 * are ordered in document order
5770 *
5771 * Returns the next element following that axis
5772 */
5773xmlNodePtr
5774xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5775 if (cur != NULL && cur->children != NULL)
5776 return cur->children ;
5777 if (cur == NULL) cur = ctxt->context->node;
5778 if (cur == NULL) return(NULL) ; /* ERROR */
5779 if (cur->next != NULL) return(cur->next) ;
5780 do {
5781 cur = cur->parent;
5782 if (cur == NULL) return(NULL);
5783 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5784 if (cur->next != NULL) return(cur->next);
5785 } while (cur != NULL);
5786 return(cur);
5787}
5788
5789/*
5790 * xmlXPathIsAncestor:
5791 * @ancestor: the ancestor node
5792 * @node: the current node
5793 *
5794 * Check that @ancestor is a @node's ancestor
5795 *
5796 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5797 */
5798static int
5799xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5800 if ((ancestor == NULL) || (node == NULL)) return(0);
5801 /* nodes need to be in the same document */
5802 if (ancestor->doc != node->doc) return(0);
5803 /* avoid searching if ancestor or node is the root node */
5804 if (ancestor == (xmlNodePtr) node->doc) return(1);
5805 if (node == (xmlNodePtr) ancestor->doc) return(0);
5806 while (node->parent != NULL) {
5807 if (node->parent == ancestor)
5808 return(1);
5809 node = node->parent;
5810 }
5811 return(0);
5812}
5813
5814/**
5815 * xmlXPathNextPreceding:
5816 * @ctxt: the XPath Parser context
5817 * @cur: the current node in the traversal
5818 *
5819 * Traversal function for the "preceding" direction
5820 * the preceding axis contains all nodes in the same document as the context
5821 * node that are before the context node in document order, excluding any
5822 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5823 * ordered in reverse document order
5824 *
5825 * Returns the next element following that axis
5826 */
5827xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005828xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5829{
Owen Taylor3473f882001-02-23 17:55:21 +00005830 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005831 cur = ctxt->context->node;
5832 if (cur == NULL)
5833 return (NULL);
5834 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5835 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005836 do {
5837 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005838 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5839 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005840 }
5841
5842 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005843 if (cur == NULL)
5844 return (NULL);
5845 if (cur == ctxt->context->doc->children)
5846 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005847 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005848 return (cur);
5849}
5850
5851/**
5852 * xmlXPathNextPrecedingInternal:
5853 * @ctxt: the XPath Parser context
5854 * @cur: the current node in the traversal
5855 *
5856 * Traversal function for the "preceding" direction
5857 * the preceding axis contains all nodes in the same document as the context
5858 * node that are before the context node in document order, excluding any
5859 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5860 * ordered in reverse document order
5861 * This is a faster implementation but internal only since it requires a
5862 * state kept in the parser context: ctxt->ancestor.
5863 *
5864 * Returns the next element following that axis
5865 */
5866static xmlNodePtr
5867xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5868 xmlNodePtr cur)
5869{
5870 if (cur == NULL) {
5871 cur = ctxt->context->node;
5872 if (cur == NULL)
5873 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005874 if (cur->type == XML_NAMESPACE_DECL)
5875 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005876 ctxt->ancestor = cur->parent;
5877 }
5878 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5879 cur = cur->prev;
5880 while (cur->prev == NULL) {
5881 cur = cur->parent;
5882 if (cur == NULL)
5883 return (NULL);
5884 if (cur == ctxt->context->doc->children)
5885 return (NULL);
5886 if (cur != ctxt->ancestor)
5887 return (cur);
5888 ctxt->ancestor = cur->parent;
5889 }
5890 cur = cur->prev;
5891 while (cur->last != NULL)
5892 cur = cur->last;
5893 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005894}
5895
5896/**
5897 * xmlXPathNextNamespace:
5898 * @ctxt: the XPath Parser context
5899 * @cur: the current attribute in the traversal
5900 *
5901 * Traversal function for the "namespace" direction
5902 * the namespace axis contains the namespace nodes of the context node;
5903 * the order of nodes on this axis is implementation-defined; the axis will
5904 * be empty unless the context node is an element
5905 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005906 * We keep the XML namespace node at the end of the list.
5907 *
Owen Taylor3473f882001-02-23 17:55:21 +00005908 * Returns the next element following that axis
5909 */
5910xmlNodePtr
5911xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5912 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005913 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005914 if (ctxt->context->tmpNsList != NULL)
5915 xmlFree(ctxt->context->tmpNsList);
5916 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005917 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005918 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005919 if (ctxt->context->tmpNsList != NULL) {
5920 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5921 ctxt->context->tmpNsNr++;
5922 }
5923 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005924 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005925 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005926 if (ctxt->context->tmpNsNr > 0) {
5927 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5928 } else {
5929 if (ctxt->context->tmpNsList != NULL)
5930 xmlFree(ctxt->context->tmpNsList);
5931 ctxt->context->tmpNsList = NULL;
5932 return(NULL);
5933 }
Owen Taylor3473f882001-02-23 17:55:21 +00005934}
5935
5936/**
5937 * xmlXPathNextAttribute:
5938 * @ctxt: the XPath Parser context
5939 * @cur: the current attribute in the traversal
5940 *
5941 * Traversal function for the "attribute" direction
5942 * TODO: support DTD inherited default attributes
5943 *
5944 * Returns the next element following that axis
5945 */
5946xmlNodePtr
5947xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005948 if (ctxt->context->node == NULL)
5949 return(NULL);
5950 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5951 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005952 if (cur == NULL) {
5953 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5954 return(NULL);
5955 return((xmlNodePtr)ctxt->context->node->properties);
5956 }
5957 return((xmlNodePtr)cur->next);
5958}
5959
5960/************************************************************************
5961 * *
5962 * NodeTest Functions *
5963 * *
5964 ************************************************************************/
5965
Owen Taylor3473f882001-02-23 17:55:21 +00005966#define IS_FUNCTION 200
5967
Owen Taylor3473f882001-02-23 17:55:21 +00005968
5969/************************************************************************
5970 * *
5971 * Implicit tree core function library *
5972 * *
5973 ************************************************************************/
5974
5975/**
5976 * xmlXPathRoot:
5977 * @ctxt: the XPath Parser context
5978 *
5979 * Initialize the context to the root of the document
5980 */
5981void
5982xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5983 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5984 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5985}
5986
5987/************************************************************************
5988 * *
5989 * The explicit core function library *
5990 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5991 * *
5992 ************************************************************************/
5993
5994
5995/**
5996 * xmlXPathLastFunction:
5997 * @ctxt: the XPath Parser context
5998 * @nargs: the number of arguments
5999 *
6000 * Implement the last() XPath function
6001 * number last()
6002 * The last function returns the number of nodes in the context node list.
6003 */
6004void
6005xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6006 CHECK_ARITY(0);
6007 if (ctxt->context->contextSize >= 0) {
6008 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
6009#ifdef DEBUG_EXPR
6010 xmlGenericError(xmlGenericErrorContext,
6011 "last() : %d\n", ctxt->context->contextSize);
6012#endif
6013 } else {
6014 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6015 }
6016}
6017
6018/**
6019 * xmlXPathPositionFunction:
6020 * @ctxt: the XPath Parser context
6021 * @nargs: the number of arguments
6022 *
6023 * Implement the position() XPath function
6024 * number position()
6025 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006026 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00006027 * will be equal to last().
6028 */
6029void
6030xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6031 CHECK_ARITY(0);
6032 if (ctxt->context->proximityPosition >= 0) {
6033 valuePush(ctxt,
6034 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6035#ifdef DEBUG_EXPR
6036 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6037 ctxt->context->proximityPosition);
6038#endif
6039 } else {
6040 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6041 }
6042}
6043
6044/**
6045 * xmlXPathCountFunction:
6046 * @ctxt: the XPath Parser context
6047 * @nargs: the number of arguments
6048 *
6049 * Implement the count() XPath function
6050 * number count(node-set)
6051 */
6052void
6053xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6054 xmlXPathObjectPtr cur;
6055
6056 CHECK_ARITY(1);
6057 if ((ctxt->value == NULL) ||
6058 ((ctxt->value->type != XPATH_NODESET) &&
6059 (ctxt->value->type != XPATH_XSLT_TREE)))
6060 XP_ERROR(XPATH_INVALID_TYPE);
6061 cur = valuePop(ctxt);
6062
Daniel Veillard911f49a2001-04-07 15:39:35 +00006063 if ((cur == NULL) || (cur->nodesetval == NULL))
6064 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006065 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006066 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006067 } else {
6068 if ((cur->nodesetval->nodeNr != 1) ||
6069 (cur->nodesetval->nodeTab == NULL)) {
6070 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6071 } else {
6072 xmlNodePtr tmp;
6073 int i = 0;
6074
6075 tmp = cur->nodesetval->nodeTab[0];
6076 if (tmp != NULL) {
6077 tmp = tmp->children;
6078 while (tmp != NULL) {
6079 tmp = tmp->next;
6080 i++;
6081 }
6082 }
6083 valuePush(ctxt, xmlXPathNewFloat((double) i));
6084 }
6085 }
Owen Taylor3473f882001-02-23 17:55:21 +00006086 xmlXPathFreeObject(cur);
6087}
6088
6089/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006090 * xmlXPathGetElementsByIds:
6091 * @doc: the document
6092 * @ids: a whitespace separated list of IDs
6093 *
6094 * Selects elements by their unique ID.
6095 *
6096 * Returns a node-set of selected elements.
6097 */
6098static xmlNodeSetPtr
6099xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6100 xmlNodeSetPtr ret;
6101 const xmlChar *cur = ids;
6102 xmlChar *ID;
6103 xmlAttrPtr attr;
6104 xmlNodePtr elem = NULL;
6105
Daniel Veillard7a985a12003-07-06 17:57:42 +00006106 if (ids == NULL) return(NULL);
6107
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006108 ret = xmlXPathNodeSetCreate(NULL);
6109
William M. Brack76e95df2003-10-18 16:20:14 +00006110 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006111 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006112 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006113 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006114
6115 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006116 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00006117 /*
6118 * We used to check the fact that the value passed
6119 * was an NCName, but this generated much troubles for
6120 * me and Aleksey Sanin, people blatantly violated that
6121 * constaint, like Visa3D spec.
6122 * if (xmlValidateNCName(ID, 1) == 0)
6123 */
6124 attr = xmlGetID(doc, ID);
6125 if (attr != NULL) {
6126 if (attr->type == XML_ATTRIBUTE_NODE)
6127 elem = attr->parent;
6128 else if (attr->type == XML_ELEMENT_NODE)
6129 elem = (xmlNodePtr) attr;
6130 else
6131 elem = NULL;
6132 if (elem != NULL)
6133 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00006134 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006135 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006136 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006137
William M. Brack76e95df2003-10-18 16:20:14 +00006138 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006139 ids = cur;
6140 }
6141 return(ret);
6142}
6143
6144/**
Owen Taylor3473f882001-02-23 17:55:21 +00006145 * xmlXPathIdFunction:
6146 * @ctxt: the XPath Parser context
6147 * @nargs: the number of arguments
6148 *
6149 * Implement the id() XPath function
6150 * node-set id(object)
6151 * The id function selects elements by their unique ID
6152 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6153 * then the result is the union of the result of applying id to the
6154 * string value of each of the nodes in the argument node-set. When the
6155 * argument to id is of any other type, the argument is converted to a
6156 * string as if by a call to the string function; the string is split
6157 * into a whitespace-separated list of tokens (whitespace is any sequence
6158 * of characters matching the production S); the result is a node-set
6159 * containing the elements in the same document as the context node that
6160 * have a unique ID equal to any of the tokens in the list.
6161 */
6162void
6163xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006164 xmlChar *tokens;
6165 xmlNodeSetPtr ret;
6166 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006167
6168 CHECK_ARITY(1);
6169 obj = valuePop(ctxt);
6170 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006171 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006172 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006173 int i;
6174
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006175 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006176
Daniel Veillard911f49a2001-04-07 15:39:35 +00006177 if (obj->nodesetval != NULL) {
6178 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006179 tokens =
6180 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6181 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6182 ret = xmlXPathNodeSetMerge(ret, ns);
6183 xmlXPathFreeNodeSet(ns);
6184 if (tokens != NULL)
6185 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006186 }
Owen Taylor3473f882001-02-23 17:55:21 +00006187 }
6188
6189 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006190 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006191 return;
6192 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006193 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006194
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006195 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6196 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006197
Owen Taylor3473f882001-02-23 17:55:21 +00006198 xmlXPathFreeObject(obj);
6199 return;
6200}
6201
6202/**
6203 * xmlXPathLocalNameFunction:
6204 * @ctxt: the XPath Parser context
6205 * @nargs: the number of arguments
6206 *
6207 * Implement the local-name() XPath function
6208 * string local-name(node-set?)
6209 * The local-name function returns a string containing the local part
6210 * of the name of the node in the argument node-set that is first in
6211 * document order. If the node-set is empty or the first node has no
6212 * name, an empty string is returned. If the argument is omitted it
6213 * defaults to the context node.
6214 */
6215void
6216xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6217 xmlXPathObjectPtr cur;
6218
6219 if (nargs == 0) {
6220 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6221 nargs = 1;
6222 }
6223
6224 CHECK_ARITY(1);
6225 if ((ctxt->value == NULL) ||
6226 ((ctxt->value->type != XPATH_NODESET) &&
6227 (ctxt->value->type != XPATH_XSLT_TREE)))
6228 XP_ERROR(XPATH_INVALID_TYPE);
6229 cur = valuePop(ctxt);
6230
Daniel Veillard911f49a2001-04-07 15:39:35 +00006231 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006232 valuePush(ctxt, xmlXPathNewCString(""));
6233 } else {
6234 int i = 0; /* Should be first in document order !!!!! */
6235 switch (cur->nodesetval->nodeTab[i]->type) {
6236 case XML_ELEMENT_NODE:
6237 case XML_ATTRIBUTE_NODE:
6238 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006239 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6240 valuePush(ctxt, xmlXPathNewCString(""));
6241 else
6242 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006243 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6244 break;
6245 case XML_NAMESPACE_DECL:
6246 valuePush(ctxt, xmlXPathNewString(
6247 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6248 break;
6249 default:
6250 valuePush(ctxt, xmlXPathNewCString(""));
6251 }
6252 }
6253 xmlXPathFreeObject(cur);
6254}
6255
6256/**
6257 * xmlXPathNamespaceURIFunction:
6258 * @ctxt: the XPath Parser context
6259 * @nargs: the number of arguments
6260 *
6261 * Implement the namespace-uri() XPath function
6262 * string namespace-uri(node-set?)
6263 * The namespace-uri function returns a string containing the
6264 * namespace URI of the expanded name of the node in the argument
6265 * node-set that is first in document order. If the node-set is empty,
6266 * the first node has no name, or the expanded name has no namespace
6267 * URI, an empty string is returned. If the argument is omitted it
6268 * defaults to the context node.
6269 */
6270void
6271xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6272 xmlXPathObjectPtr cur;
6273
6274 if (nargs == 0) {
6275 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6276 nargs = 1;
6277 }
6278 CHECK_ARITY(1);
6279 if ((ctxt->value == NULL) ||
6280 ((ctxt->value->type != XPATH_NODESET) &&
6281 (ctxt->value->type != XPATH_XSLT_TREE)))
6282 XP_ERROR(XPATH_INVALID_TYPE);
6283 cur = valuePop(ctxt);
6284
Daniel Veillard911f49a2001-04-07 15:39:35 +00006285 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006286 valuePush(ctxt, xmlXPathNewCString(""));
6287 } else {
6288 int i = 0; /* Should be first in document order !!!!! */
6289 switch (cur->nodesetval->nodeTab[i]->type) {
6290 case XML_ELEMENT_NODE:
6291 case XML_ATTRIBUTE_NODE:
6292 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6293 valuePush(ctxt, xmlXPathNewCString(""));
6294 else
6295 valuePush(ctxt, xmlXPathNewString(
6296 cur->nodesetval->nodeTab[i]->ns->href));
6297 break;
6298 default:
6299 valuePush(ctxt, xmlXPathNewCString(""));
6300 }
6301 }
6302 xmlXPathFreeObject(cur);
6303}
6304
6305/**
6306 * xmlXPathNameFunction:
6307 * @ctxt: the XPath Parser context
6308 * @nargs: the number of arguments
6309 *
6310 * Implement the name() XPath function
6311 * string name(node-set?)
6312 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006313 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006314 * order. The QName must represent the name with respect to the namespace
6315 * declarations in effect on the node whose name is being represented.
6316 * Typically, this will be the form in which the name occurred in the XML
6317 * source. This need not be the case if there are namespace declarations
6318 * in effect on the node that associate multiple prefixes with the same
6319 * namespace. However, an implementation may include information about
6320 * the original prefix in its representation of nodes; in this case, an
6321 * implementation can ensure that the returned string is always the same
6322 * as the QName used in the XML source. If the argument it omitted it
6323 * defaults to the context node.
6324 * Libxml keep the original prefix so the "real qualified name" used is
6325 * returned.
6326 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006327static void
Daniel Veillard04383752001-07-08 14:27:15 +00006328xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6329{
Owen Taylor3473f882001-02-23 17:55:21 +00006330 xmlXPathObjectPtr cur;
6331
6332 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006333 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6334 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006335 }
6336
6337 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006338 if ((ctxt->value == NULL) ||
6339 ((ctxt->value->type != XPATH_NODESET) &&
6340 (ctxt->value->type != XPATH_XSLT_TREE)))
6341 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006342 cur = valuePop(ctxt);
6343
Daniel Veillard911f49a2001-04-07 15:39:35 +00006344 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006345 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006346 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006347 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006348
Daniel Veillard04383752001-07-08 14:27:15 +00006349 switch (cur->nodesetval->nodeTab[i]->type) {
6350 case XML_ELEMENT_NODE:
6351 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006352 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6353 valuePush(ctxt, xmlXPathNewCString(""));
6354 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6355 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006356 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006357 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006358
Daniel Veillard652d8a92003-02-04 19:28:49 +00006359 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006360 xmlChar *fullname;
6361
6362 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6363 cur->nodesetval->nodeTab[i]->ns->prefix,
6364 NULL, 0);
6365 if (fullname == cur->nodesetval->nodeTab[i]->name)
6366 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6367 if (fullname == NULL) {
6368 XP_ERROR(XPATH_MEMORY_ERROR);
6369 }
6370 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006371 }
6372 break;
6373 default:
6374 valuePush(ctxt,
6375 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6376 xmlXPathLocalNameFunction(ctxt, 1);
6377 }
Owen Taylor3473f882001-02-23 17:55:21 +00006378 }
6379 xmlXPathFreeObject(cur);
6380}
6381
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006382
6383/**
Owen Taylor3473f882001-02-23 17:55:21 +00006384 * xmlXPathStringFunction:
6385 * @ctxt: the XPath Parser context
6386 * @nargs: the number of arguments
6387 *
6388 * Implement the string() XPath function
6389 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006390 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006391 * - A node-set is converted to a string by returning the value of
6392 * the node in the node-set that is first in document order.
6393 * If the node-set is empty, an empty string is returned.
6394 * - A number is converted to a string as follows
6395 * + NaN is converted to the string NaN
6396 * + positive zero is converted to the string 0
6397 * + negative zero is converted to the string 0
6398 * + positive infinity is converted to the string Infinity
6399 * + negative infinity is converted to the string -Infinity
6400 * + if the number is an integer, the number is represented in
6401 * decimal form as a Number with no decimal point and no leading
6402 * zeros, preceded by a minus sign (-) if the number is negative
6403 * + otherwise, the number is represented in decimal form as a
6404 * Number including a decimal point with at least one digit
6405 * before the decimal point and at least one digit after the
6406 * decimal point, preceded by a minus sign (-) if the number
6407 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006408 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006409 * before the decimal point; beyond the one required digit
6410 * after the decimal point there must be as many, but only as
6411 * many, more digits as are needed to uniquely distinguish the
6412 * number from all other IEEE 754 numeric values.
6413 * - The boolean false value is converted to the string false.
6414 * The boolean true value is converted to the string true.
6415 *
6416 * If the argument is omitted, it defaults to a node-set with the
6417 * context node as its only member.
6418 */
6419void
6420xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6421 xmlXPathObjectPtr cur;
6422
6423 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006424 valuePush(ctxt,
6425 xmlXPathWrapString(
6426 xmlXPathCastNodeToString(ctxt->context->node)));
6427 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006428 }
6429
6430 CHECK_ARITY(1);
6431 cur = valuePop(ctxt);
6432 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006433 cur = xmlXPathConvertString(cur);
6434 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006435}
6436
6437/**
6438 * xmlXPathStringLengthFunction:
6439 * @ctxt: the XPath Parser context
6440 * @nargs: the number of arguments
6441 *
6442 * Implement the string-length() XPath function
6443 * number string-length(string?)
6444 * The string-length returns the number of characters in the string
6445 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6446 * the context node converted to a string, in other words the value
6447 * of the context node.
6448 */
6449void
6450xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6451 xmlXPathObjectPtr cur;
6452
6453 if (nargs == 0) {
6454 if (ctxt->context->node == NULL) {
6455 valuePush(ctxt, xmlXPathNewFloat(0));
6456 } else {
6457 xmlChar *content;
6458
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006459 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006460 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006461 xmlFree(content);
6462 }
6463 return;
6464 }
6465 CHECK_ARITY(1);
6466 CAST_TO_STRING;
6467 CHECK_TYPE(XPATH_STRING);
6468 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006469 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006470 xmlXPathFreeObject(cur);
6471}
6472
6473/**
6474 * xmlXPathConcatFunction:
6475 * @ctxt: the XPath Parser context
6476 * @nargs: the number of arguments
6477 *
6478 * Implement the concat() XPath function
6479 * string concat(string, string, string*)
6480 * The concat function returns the concatenation of its arguments.
6481 */
6482void
6483xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6484 xmlXPathObjectPtr cur, newobj;
6485 xmlChar *tmp;
6486
6487 if (nargs < 2) {
6488 CHECK_ARITY(2);
6489 }
6490
6491 CAST_TO_STRING;
6492 cur = valuePop(ctxt);
6493 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6494 xmlXPathFreeObject(cur);
6495 return;
6496 }
6497 nargs--;
6498
6499 while (nargs > 0) {
6500 CAST_TO_STRING;
6501 newobj = valuePop(ctxt);
6502 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6503 xmlXPathFreeObject(newobj);
6504 xmlXPathFreeObject(cur);
6505 XP_ERROR(XPATH_INVALID_TYPE);
6506 }
6507 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6508 newobj->stringval = cur->stringval;
6509 cur->stringval = tmp;
6510
6511 xmlXPathFreeObject(newobj);
6512 nargs--;
6513 }
6514 valuePush(ctxt, cur);
6515}
6516
6517/**
6518 * xmlXPathContainsFunction:
6519 * @ctxt: the XPath Parser context
6520 * @nargs: the number of arguments
6521 *
6522 * Implement the contains() XPath function
6523 * boolean contains(string, string)
6524 * The contains function returns true if the first argument string
6525 * contains the second argument string, and otherwise returns false.
6526 */
6527void
6528xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6529 xmlXPathObjectPtr hay, needle;
6530
6531 CHECK_ARITY(2);
6532 CAST_TO_STRING;
6533 CHECK_TYPE(XPATH_STRING);
6534 needle = valuePop(ctxt);
6535 CAST_TO_STRING;
6536 hay = valuePop(ctxt);
6537 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6538 xmlXPathFreeObject(hay);
6539 xmlXPathFreeObject(needle);
6540 XP_ERROR(XPATH_INVALID_TYPE);
6541 }
6542 if (xmlStrstr(hay->stringval, needle->stringval))
6543 valuePush(ctxt, xmlXPathNewBoolean(1));
6544 else
6545 valuePush(ctxt, xmlXPathNewBoolean(0));
6546 xmlXPathFreeObject(hay);
6547 xmlXPathFreeObject(needle);
6548}
6549
6550/**
6551 * xmlXPathStartsWithFunction:
6552 * @ctxt: the XPath Parser context
6553 * @nargs: the number of arguments
6554 *
6555 * Implement the starts-with() XPath function
6556 * boolean starts-with(string, string)
6557 * The starts-with function returns true if the first argument string
6558 * starts with the second argument string, and otherwise returns false.
6559 */
6560void
6561xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6562 xmlXPathObjectPtr hay, needle;
6563 int n;
6564
6565 CHECK_ARITY(2);
6566 CAST_TO_STRING;
6567 CHECK_TYPE(XPATH_STRING);
6568 needle = valuePop(ctxt);
6569 CAST_TO_STRING;
6570 hay = valuePop(ctxt);
6571 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6572 xmlXPathFreeObject(hay);
6573 xmlXPathFreeObject(needle);
6574 XP_ERROR(XPATH_INVALID_TYPE);
6575 }
6576 n = xmlStrlen(needle->stringval);
6577 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6578 valuePush(ctxt, xmlXPathNewBoolean(0));
6579 else
6580 valuePush(ctxt, xmlXPathNewBoolean(1));
6581 xmlXPathFreeObject(hay);
6582 xmlXPathFreeObject(needle);
6583}
6584
6585/**
6586 * xmlXPathSubstringFunction:
6587 * @ctxt: the XPath Parser context
6588 * @nargs: the number of arguments
6589 *
6590 * Implement the substring() XPath function
6591 * string substring(string, number, number?)
6592 * The substring function returns the substring of the first argument
6593 * starting at the position specified in the second argument with
6594 * length specified in the third argument. For example,
6595 * substring("12345",2,3) returns "234". If the third argument is not
6596 * specified, it returns the substring starting at the position specified
6597 * in the second argument and continuing to the end of the string. For
6598 * example, substring("12345",2) returns "2345". More precisely, each
6599 * character in the string (see [3.6 Strings]) is considered to have a
6600 * numeric position: the position of the first character is 1, the position
6601 * of the second character is 2 and so on. The returned substring contains
6602 * those characters for which the position of the character is greater than
6603 * or equal to the second argument and, if the third argument is specified,
6604 * less than the sum of the second and third arguments; the comparisons
6605 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6606 * - substring("12345", 1.5, 2.6) returns "234"
6607 * - substring("12345", 0, 3) returns "12"
6608 * - substring("12345", 0 div 0, 3) returns ""
6609 * - substring("12345", 1, 0 div 0) returns ""
6610 * - substring("12345", -42, 1 div 0) returns "12345"
6611 * - substring("12345", -1 div 0, 1 div 0) returns ""
6612 */
6613void
6614xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6615 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006616 double le=0, in;
6617 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006618 xmlChar *ret;
6619
Owen Taylor3473f882001-02-23 17:55:21 +00006620 if (nargs < 2) {
6621 CHECK_ARITY(2);
6622 }
6623 if (nargs > 3) {
6624 CHECK_ARITY(3);
6625 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006626 /*
6627 * take care of possible last (position) argument
6628 */
Owen Taylor3473f882001-02-23 17:55:21 +00006629 if (nargs == 3) {
6630 CAST_TO_NUMBER;
6631 CHECK_TYPE(XPATH_NUMBER);
6632 len = valuePop(ctxt);
6633 le = len->floatval;
6634 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006635 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006636
Owen Taylor3473f882001-02-23 17:55:21 +00006637 CAST_TO_NUMBER;
6638 CHECK_TYPE(XPATH_NUMBER);
6639 start = valuePop(ctxt);
6640 in = start->floatval;
6641 xmlXPathFreeObject(start);
6642 CAST_TO_STRING;
6643 CHECK_TYPE(XPATH_STRING);
6644 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006645 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006646
Daniel Veillard97ac1312001-05-30 19:14:17 +00006647 /*
6648 * If last pos not present, calculate last position
6649 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006650 if (nargs != 3) {
6651 le = (double)m;
6652 if (in < 1.0)
6653 in = 1.0;
6654 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006655
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006656 /* Need to check for the special cases where either
6657 * the index is NaN, the length is NaN, or both
6658 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006659 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006660 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006661 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006662 * To meet the requirements of the spec, the arguments
6663 * must be converted to integer format before
6664 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006665 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006666 * First we go to integer form, rounding up
6667 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006668 */
6669 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006670 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006671
Daniel Veillard9e412302002-06-10 15:59:44 +00006672 if (xmlXPathIsInf(le) == 1) {
6673 l = m;
6674 if (i < 1)
6675 i = 1;
6676 }
6677 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6678 l = 0;
6679 else {
6680 l = (int) le;
6681 if (((double)l)+0.5 <= le) l++;
6682 }
6683
6684 /* Now we normalize inidices */
6685 i -= 1;
6686 l += i;
6687 if (i < 0)
6688 i = 0;
6689 if (l > m)
6690 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006691
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006692 /* number of chars to copy */
6693 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006694
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006695 ret = xmlUTF8Strsub(str->stringval, i, l);
6696 }
6697 else {
6698 ret = NULL;
6699 }
6700
Owen Taylor3473f882001-02-23 17:55:21 +00006701 if (ret == NULL)
6702 valuePush(ctxt, xmlXPathNewCString(""));
6703 else {
6704 valuePush(ctxt, xmlXPathNewString(ret));
6705 xmlFree(ret);
6706 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006707
Owen Taylor3473f882001-02-23 17:55:21 +00006708 xmlXPathFreeObject(str);
6709}
6710
6711/**
6712 * xmlXPathSubstringBeforeFunction:
6713 * @ctxt: the XPath Parser context
6714 * @nargs: the number of arguments
6715 *
6716 * Implement the substring-before() XPath function
6717 * string substring-before(string, string)
6718 * The substring-before function returns the substring of the first
6719 * argument string that precedes the first occurrence of the second
6720 * argument string in the first argument string, or the empty string
6721 * if the first argument string does not contain the second argument
6722 * string. For example, substring-before("1999/04/01","/") returns 1999.
6723 */
6724void
6725xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6726 xmlXPathObjectPtr str;
6727 xmlXPathObjectPtr find;
6728 xmlBufferPtr target;
6729 const xmlChar *point;
6730 int offset;
6731
6732 CHECK_ARITY(2);
6733 CAST_TO_STRING;
6734 find = valuePop(ctxt);
6735 CAST_TO_STRING;
6736 str = valuePop(ctxt);
6737
6738 target = xmlBufferCreate();
6739 if (target) {
6740 point = xmlStrstr(str->stringval, find->stringval);
6741 if (point) {
6742 offset = (int)(point - str->stringval);
6743 xmlBufferAdd(target, str->stringval, offset);
6744 }
6745 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6746 xmlBufferFree(target);
6747 }
6748
6749 xmlXPathFreeObject(str);
6750 xmlXPathFreeObject(find);
6751}
6752
6753/**
6754 * xmlXPathSubstringAfterFunction:
6755 * @ctxt: the XPath Parser context
6756 * @nargs: the number of arguments
6757 *
6758 * Implement the substring-after() XPath function
6759 * string substring-after(string, string)
6760 * The substring-after function returns the substring of the first
6761 * argument string that follows the first occurrence of the second
6762 * argument string in the first argument string, or the empty stringi
6763 * if the first argument string does not contain the second argument
6764 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6765 * and substring-after("1999/04/01","19") returns 99/04/01.
6766 */
6767void
6768xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6769 xmlXPathObjectPtr str;
6770 xmlXPathObjectPtr find;
6771 xmlBufferPtr target;
6772 const xmlChar *point;
6773 int offset;
6774
6775 CHECK_ARITY(2);
6776 CAST_TO_STRING;
6777 find = valuePop(ctxt);
6778 CAST_TO_STRING;
6779 str = valuePop(ctxt);
6780
6781 target = xmlBufferCreate();
6782 if (target) {
6783 point = xmlStrstr(str->stringval, find->stringval);
6784 if (point) {
6785 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6786 xmlBufferAdd(target, &str->stringval[offset],
6787 xmlStrlen(str->stringval) - offset);
6788 }
6789 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6790 xmlBufferFree(target);
6791 }
6792
6793 xmlXPathFreeObject(str);
6794 xmlXPathFreeObject(find);
6795}
6796
6797/**
6798 * xmlXPathNormalizeFunction:
6799 * @ctxt: the XPath Parser context
6800 * @nargs: the number of arguments
6801 *
6802 * Implement the normalize-space() XPath function
6803 * string normalize-space(string?)
6804 * The normalize-space function returns the argument string with white
6805 * space normalized by stripping leading and trailing whitespace
6806 * and replacing sequences of whitespace characters by a single
6807 * space. Whitespace characters are the same allowed by the S production
6808 * in XML. If the argument is omitted, it defaults to the context
6809 * node converted to a string, in other words the value of the context node.
6810 */
6811void
6812xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6813 xmlXPathObjectPtr obj = NULL;
6814 xmlChar *source = NULL;
6815 xmlBufferPtr target;
6816 xmlChar blank;
6817
6818 if (nargs == 0) {
6819 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006820 valuePush(ctxt,
6821 xmlXPathWrapString(
6822 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006823 nargs = 1;
6824 }
6825
6826 CHECK_ARITY(1);
6827 CAST_TO_STRING;
6828 CHECK_TYPE(XPATH_STRING);
6829 obj = valuePop(ctxt);
6830 source = obj->stringval;
6831
6832 target = xmlBufferCreate();
6833 if (target && source) {
6834
6835 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006836 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006837 source++;
6838
6839 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6840 blank = 0;
6841 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006842 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006843 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006844 } else {
6845 if (blank) {
6846 xmlBufferAdd(target, &blank, 1);
6847 blank = 0;
6848 }
6849 xmlBufferAdd(target, source, 1);
6850 }
6851 source++;
6852 }
6853
6854 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6855 xmlBufferFree(target);
6856 }
6857 xmlXPathFreeObject(obj);
6858}
6859
6860/**
6861 * xmlXPathTranslateFunction:
6862 * @ctxt: the XPath Parser context
6863 * @nargs: the number of arguments
6864 *
6865 * Implement the translate() XPath function
6866 * string translate(string, string, string)
6867 * The translate function returns the first argument string with
6868 * occurrences of characters in the second argument string replaced
6869 * by the character at the corresponding position in the third argument
6870 * string. For example, translate("bar","abc","ABC") returns the string
6871 * BAr. If there is a character in the second argument string with no
6872 * character at a corresponding position in the third argument string
6873 * (because the second argument string is longer than the third argument
6874 * string), then occurrences of that character in the first argument
6875 * string are removed. For example, translate("--aaa--","abc-","ABC")
6876 * returns "AAA". If a character occurs more than once in second
6877 * argument string, then the first occurrence determines the replacement
6878 * character. If the third argument string is longer than the second
6879 * argument string, then excess characters are ignored.
6880 */
6881void
6882xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006883 xmlXPathObjectPtr str;
6884 xmlXPathObjectPtr from;
6885 xmlXPathObjectPtr to;
6886 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006887 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006888 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00006889 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006890 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006891
Daniel Veillarde043ee12001-04-16 14:08:07 +00006892 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006893
Daniel Veillarde043ee12001-04-16 14:08:07 +00006894 CAST_TO_STRING;
6895 to = valuePop(ctxt);
6896 CAST_TO_STRING;
6897 from = valuePop(ctxt);
6898 CAST_TO_STRING;
6899 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006900
Daniel Veillarde043ee12001-04-16 14:08:07 +00006901 target = xmlBufferCreate();
6902 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006903 max = xmlUTF8Strlen(to->stringval);
6904 for (cptr = str->stringval; (ch=*cptr); ) {
6905 offset = xmlUTF8Strloc(from->stringval, cptr);
6906 if (offset >= 0) {
6907 if (offset < max) {
6908 point = xmlUTF8Strpos(to->stringval, offset);
6909 if (point)
6910 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6911 }
6912 } else
6913 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6914
6915 /* Step to next character in input */
6916 cptr++;
6917 if ( ch & 0x80 ) {
6918 /* if not simple ascii, verify proper format */
6919 if ( (ch & 0xc0) != 0xc0 ) {
6920 xmlGenericError(xmlGenericErrorContext,
6921 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6922 break;
6923 }
6924 /* then skip over remaining bytes for this char */
6925 while ( (ch <<= 1) & 0x80 )
6926 if ( (*cptr++ & 0xc0) != 0x80 ) {
6927 xmlGenericError(xmlGenericErrorContext,
6928 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6929 break;
6930 }
6931 if (ch & 0x80) /* must have had error encountered */
6932 break;
6933 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006934 }
Owen Taylor3473f882001-02-23 17:55:21 +00006935 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006936 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6937 xmlBufferFree(target);
6938 xmlXPathFreeObject(str);
6939 xmlXPathFreeObject(from);
6940 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006941}
6942
6943/**
6944 * xmlXPathBooleanFunction:
6945 * @ctxt: the XPath Parser context
6946 * @nargs: the number of arguments
6947 *
6948 * Implement the boolean() XPath function
6949 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00006950 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006951 * - a number is true if and only if it is neither positive or
6952 * negative zero nor NaN
6953 * - a node-set is true if and only if it is non-empty
6954 * - a string is true if and only if its length is non-zero
6955 */
6956void
6957xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6958 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006959
6960 CHECK_ARITY(1);
6961 cur = valuePop(ctxt);
6962 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006963 cur = xmlXPathConvertBoolean(cur);
6964 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006965}
6966
6967/**
6968 * xmlXPathNotFunction:
6969 * @ctxt: the XPath Parser context
6970 * @nargs: the number of arguments
6971 *
6972 * Implement the not() XPath function
6973 * boolean not(boolean)
6974 * The not function returns true if its argument is false,
6975 * and false otherwise.
6976 */
6977void
6978xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6979 CHECK_ARITY(1);
6980 CAST_TO_BOOLEAN;
6981 CHECK_TYPE(XPATH_BOOLEAN);
6982 ctxt->value->boolval = ! ctxt->value->boolval;
6983}
6984
6985/**
6986 * xmlXPathTrueFunction:
6987 * @ctxt: the XPath Parser context
6988 * @nargs: the number of arguments
6989 *
6990 * Implement the true() XPath function
6991 * boolean true()
6992 */
6993void
6994xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6995 CHECK_ARITY(0);
6996 valuePush(ctxt, xmlXPathNewBoolean(1));
6997}
6998
6999/**
7000 * xmlXPathFalseFunction:
7001 * @ctxt: the XPath Parser context
7002 * @nargs: the number of arguments
7003 *
7004 * Implement the false() XPath function
7005 * boolean false()
7006 */
7007void
7008xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7009 CHECK_ARITY(0);
7010 valuePush(ctxt, xmlXPathNewBoolean(0));
7011}
7012
7013/**
7014 * xmlXPathLangFunction:
7015 * @ctxt: the XPath Parser context
7016 * @nargs: the number of arguments
7017 *
7018 * Implement the lang() XPath function
7019 * boolean lang(string)
7020 * The lang function returns true or false depending on whether the
7021 * language of the context node as specified by xml:lang attributes
7022 * is the same as or is a sublanguage of the language specified by
7023 * the argument string. The language of the context node is determined
7024 * by the value of the xml:lang attribute on the context node, or, if
7025 * the context node has no xml:lang attribute, by the value of the
7026 * xml:lang attribute on the nearest ancestor of the context node that
7027 * has an xml:lang attribute. If there is no such attribute, then lang
7028 * returns false. If there is such an attribute, then lang returns
7029 * true if the attribute value is equal to the argument ignoring case,
7030 * or if there is some suffix starting with - such that the attribute
7031 * value is equal to the argument ignoring that suffix of the attribute
7032 * value and ignoring case.
7033 */
7034void
7035xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7036 xmlXPathObjectPtr val;
7037 const xmlChar *theLang;
7038 const xmlChar *lang;
7039 int ret = 0;
7040 int i;
7041
7042 CHECK_ARITY(1);
7043 CAST_TO_STRING;
7044 CHECK_TYPE(XPATH_STRING);
7045 val = valuePop(ctxt);
7046 lang = val->stringval;
7047 theLang = xmlNodeGetLang(ctxt->context->node);
7048 if ((theLang != NULL) && (lang != NULL)) {
7049 for (i = 0;lang[i] != 0;i++)
7050 if (toupper(lang[i]) != toupper(theLang[i]))
7051 goto not_equal;
7052 ret = 1;
7053 }
7054not_equal:
William M. Bracka59ddb52004-02-25 08:12:32 +00007055 xmlFree((void *)theLang);
Owen Taylor3473f882001-02-23 17:55:21 +00007056 xmlXPathFreeObject(val);
7057 valuePush(ctxt, xmlXPathNewBoolean(ret));
7058}
7059
7060/**
7061 * xmlXPathNumberFunction:
7062 * @ctxt: the XPath Parser context
7063 * @nargs: the number of arguments
7064 *
7065 * Implement the number() XPath function
7066 * number number(object?)
7067 */
7068void
7069xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7070 xmlXPathObjectPtr cur;
7071 double res;
7072
7073 if (nargs == 0) {
7074 if (ctxt->context->node == NULL) {
7075 valuePush(ctxt, xmlXPathNewFloat(0.0));
7076 } else {
7077 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7078
7079 res = xmlXPathStringEvalNumber(content);
7080 valuePush(ctxt, xmlXPathNewFloat(res));
7081 xmlFree(content);
7082 }
7083 return;
7084 }
7085
7086 CHECK_ARITY(1);
7087 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007088 cur = xmlXPathConvertNumber(cur);
7089 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007090}
7091
7092/**
7093 * xmlXPathSumFunction:
7094 * @ctxt: the XPath Parser context
7095 * @nargs: the number of arguments
7096 *
7097 * Implement the sum() XPath function
7098 * number sum(node-set)
7099 * The sum function returns the sum of the values of the nodes in
7100 * the argument node-set.
7101 */
7102void
7103xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7104 xmlXPathObjectPtr cur;
7105 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007106 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007107
7108 CHECK_ARITY(1);
7109 if ((ctxt->value == NULL) ||
7110 ((ctxt->value->type != XPATH_NODESET) &&
7111 (ctxt->value->type != XPATH_XSLT_TREE)))
7112 XP_ERROR(XPATH_INVALID_TYPE);
7113 cur = valuePop(ctxt);
7114
William M. Brack08171912003-12-29 02:52:11 +00007115 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007116 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7117 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007118 }
7119 }
William M. Brack08171912003-12-29 02:52:11 +00007120 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007121 xmlXPathFreeObject(cur);
7122}
7123
7124/**
7125 * xmlXPathFloorFunction:
7126 * @ctxt: the XPath Parser context
7127 * @nargs: the number of arguments
7128 *
7129 * Implement the floor() XPath function
7130 * number floor(number)
7131 * The floor function returns the largest (closest to positive infinity)
7132 * number that is not greater than the argument and that is an integer.
7133 */
7134void
7135xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007136 double f;
7137
Owen Taylor3473f882001-02-23 17:55:21 +00007138 CHECK_ARITY(1);
7139 CAST_TO_NUMBER;
7140 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007141
7142 f = (double)((int) ctxt->value->floatval);
7143 if (f != ctxt->value->floatval) {
7144 if (ctxt->value->floatval > 0)
7145 ctxt->value->floatval = f;
7146 else
7147 ctxt->value->floatval = f - 1;
7148 }
Owen Taylor3473f882001-02-23 17:55:21 +00007149}
7150
7151/**
7152 * xmlXPathCeilingFunction:
7153 * @ctxt: the XPath Parser context
7154 * @nargs: the number of arguments
7155 *
7156 * Implement the ceiling() XPath function
7157 * number ceiling(number)
7158 * The ceiling function returns the smallest (closest to negative infinity)
7159 * number that is not less than the argument and that is an integer.
7160 */
7161void
7162xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7163 double f;
7164
7165 CHECK_ARITY(1);
7166 CAST_TO_NUMBER;
7167 CHECK_TYPE(XPATH_NUMBER);
7168
7169#if 0
7170 ctxt->value->floatval = ceil(ctxt->value->floatval);
7171#else
7172 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007173 if (f != ctxt->value->floatval) {
7174 if (ctxt->value->floatval > 0)
7175 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007176 else {
7177 if (ctxt->value->floatval < 0 && f == 0)
7178 ctxt->value->floatval = xmlXPathNZERO;
7179 else
7180 ctxt->value->floatval = f;
7181 }
7182
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007183 }
Owen Taylor3473f882001-02-23 17:55:21 +00007184#endif
7185}
7186
7187/**
7188 * xmlXPathRoundFunction:
7189 * @ctxt: the XPath Parser context
7190 * @nargs: the number of arguments
7191 *
7192 * Implement the round() XPath function
7193 * number round(number)
7194 * The round function returns the number that is closest to the
7195 * argument and that is an integer. If there are two such numbers,
7196 * then the one that is even is returned.
7197 */
7198void
7199xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7200 double f;
7201
7202 CHECK_ARITY(1);
7203 CAST_TO_NUMBER;
7204 CHECK_TYPE(XPATH_NUMBER);
7205
Daniel Veillardcda96922001-08-21 10:56:31 +00007206 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7207 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7208 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007209 (ctxt->value->floatval == 0.0))
7210 return;
7211
Owen Taylor3473f882001-02-23 17:55:21 +00007212 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007213 if (ctxt->value->floatval < 0) {
7214 if (ctxt->value->floatval < f - 0.5)
7215 ctxt->value->floatval = f - 1;
7216 else
7217 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007218 if (ctxt->value->floatval == 0)
7219 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007220 } else {
7221 if (ctxt->value->floatval < f + 0.5)
7222 ctxt->value->floatval = f;
7223 else
7224 ctxt->value->floatval = f + 1;
7225 }
Owen Taylor3473f882001-02-23 17:55:21 +00007226}
7227
7228/************************************************************************
7229 * *
7230 * The Parser *
7231 * *
7232 ************************************************************************/
7233
7234/*
William M. Brack08171912003-12-29 02:52:11 +00007235 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007236 * implementation.
7237 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007238static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007239static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007240static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007241static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007242static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7243 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007244
7245/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007246 * xmlXPathCurrentChar:
7247 * @ctxt: the XPath parser context
7248 * @cur: pointer to the beginning of the char
7249 * @len: pointer to the length of the char read
7250 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007251 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007252 * bytes in the input buffer.
7253 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007254 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007255 */
7256
7257static int
7258xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7259 unsigned char c;
7260 unsigned int val;
7261 const xmlChar *cur;
7262
7263 if (ctxt == NULL)
7264 return(0);
7265 cur = ctxt->cur;
7266
7267 /*
7268 * We are supposed to handle UTF8, check it's valid
7269 * From rfc2044: encoding of the Unicode values on UTF-8:
7270 *
7271 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7272 * 0000 0000-0000 007F 0xxxxxxx
7273 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7274 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7275 *
7276 * Check for the 0x110000 limit too
7277 */
7278 c = *cur;
7279 if (c & 0x80) {
7280 if ((cur[1] & 0xc0) != 0x80)
7281 goto encoding_error;
7282 if ((c & 0xe0) == 0xe0) {
7283
7284 if ((cur[2] & 0xc0) != 0x80)
7285 goto encoding_error;
7286 if ((c & 0xf0) == 0xf0) {
7287 if (((c & 0xf8) != 0xf0) ||
7288 ((cur[3] & 0xc0) != 0x80))
7289 goto encoding_error;
7290 /* 4-byte code */
7291 *len = 4;
7292 val = (cur[0] & 0x7) << 18;
7293 val |= (cur[1] & 0x3f) << 12;
7294 val |= (cur[2] & 0x3f) << 6;
7295 val |= cur[3] & 0x3f;
7296 } else {
7297 /* 3-byte code */
7298 *len = 3;
7299 val = (cur[0] & 0xf) << 12;
7300 val |= (cur[1] & 0x3f) << 6;
7301 val |= cur[2] & 0x3f;
7302 }
7303 } else {
7304 /* 2-byte code */
7305 *len = 2;
7306 val = (cur[0] & 0x1f) << 6;
7307 val |= cur[1] & 0x3f;
7308 }
7309 if (!IS_CHAR(val)) {
7310 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7311 }
7312 return(val);
7313 } else {
7314 /* 1-byte code */
7315 *len = 1;
7316 return((int) *cur);
7317 }
7318encoding_error:
7319 /*
William M. Brack08171912003-12-29 02:52:11 +00007320 * If we detect an UTF8 error that probably means that the
7321 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007322 * declaration header. Report the error and switch the encoding
7323 * to ISO-Latin-1 (if you don't like this policy, just declare the
7324 * encoding !)
7325 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007326 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007327 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007328}
7329
7330/**
Owen Taylor3473f882001-02-23 17:55:21 +00007331 * xmlXPathParseNCName:
7332 * @ctxt: the XPath Parser context
7333 *
7334 * parse an XML namespace non qualified name.
7335 *
7336 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7337 *
7338 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7339 * CombiningChar | Extender
7340 *
7341 * Returns the namespace name or NULL
7342 */
7343
7344xmlChar *
7345xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007346 const xmlChar *in;
7347 xmlChar *ret;
7348 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007349
Daniel Veillard2156a562001-04-28 12:24:34 +00007350 /*
7351 * Accelerator for simple ASCII names
7352 */
7353 in = ctxt->cur;
7354 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7355 ((*in >= 0x41) && (*in <= 0x5A)) ||
7356 (*in == '_')) {
7357 in++;
7358 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7359 ((*in >= 0x41) && (*in <= 0x5A)) ||
7360 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007361 (*in == '_') || (*in == '.') ||
7362 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007363 in++;
7364 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7365 (*in == '[') || (*in == ']') || (*in == ':') ||
7366 (*in == '@') || (*in == '*')) {
7367 count = in - ctxt->cur;
7368 if (count == 0)
7369 return(NULL);
7370 ret = xmlStrndup(ctxt->cur, count);
7371 ctxt->cur = in;
7372 return(ret);
7373 }
7374 }
7375 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007376}
7377
Daniel Veillard2156a562001-04-28 12:24:34 +00007378
Owen Taylor3473f882001-02-23 17:55:21 +00007379/**
7380 * xmlXPathParseQName:
7381 * @ctxt: the XPath Parser context
7382 * @prefix: a xmlChar **
7383 *
7384 * parse an XML qualified name
7385 *
7386 * [NS 5] QName ::= (Prefix ':')? LocalPart
7387 *
7388 * [NS 6] Prefix ::= NCName
7389 *
7390 * [NS 7] LocalPart ::= NCName
7391 *
7392 * Returns the function returns the local part, and prefix is updated
7393 * to get the Prefix if any.
7394 */
7395
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007396static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007397xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7398 xmlChar *ret = NULL;
7399
7400 *prefix = NULL;
7401 ret = xmlXPathParseNCName(ctxt);
7402 if (CUR == ':') {
7403 *prefix = ret;
7404 NEXT;
7405 ret = xmlXPathParseNCName(ctxt);
7406 }
7407 return(ret);
7408}
7409
7410/**
7411 * xmlXPathParseName:
7412 * @ctxt: the XPath Parser context
7413 *
7414 * parse an XML name
7415 *
7416 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7417 * CombiningChar | Extender
7418 *
7419 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7420 *
7421 * Returns the namespace name or NULL
7422 */
7423
7424xmlChar *
7425xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007426 const xmlChar *in;
7427 xmlChar *ret;
7428 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007429
Daniel Veillard61d80a22001-04-27 17:13:01 +00007430 /*
7431 * Accelerator for simple ASCII names
7432 */
7433 in = ctxt->cur;
7434 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7435 ((*in >= 0x41) && (*in <= 0x5A)) ||
7436 (*in == '_') || (*in == ':')) {
7437 in++;
7438 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7439 ((*in >= 0x41) && (*in <= 0x5A)) ||
7440 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007441 (*in == '_') || (*in == '-') ||
7442 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007443 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007444 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007445 count = in - ctxt->cur;
7446 ret = xmlStrndup(ctxt->cur, count);
7447 ctxt->cur = in;
7448 return(ret);
7449 }
7450 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007451 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007452}
7453
Daniel Veillard61d80a22001-04-27 17:13:01 +00007454static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007455xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007456 xmlChar buf[XML_MAX_NAMELEN + 5];
7457 int len = 0, l;
7458 int c;
7459
7460 /*
7461 * Handler for more complex cases
7462 */
7463 c = CUR_CHAR(l);
7464 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007465 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7466 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007467 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007468 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007469 return(NULL);
7470 }
7471
7472 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7473 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7474 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007475 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007476 (IS_COMBINING(c)) ||
7477 (IS_EXTENDER(c)))) {
7478 COPY_BUF(l,buf,len,c);
7479 NEXTL(l);
7480 c = CUR_CHAR(l);
7481 if (len >= XML_MAX_NAMELEN) {
7482 /*
7483 * Okay someone managed to make a huge name, so he's ready to pay
7484 * for the processing speed.
7485 */
7486 xmlChar *buffer;
7487 int max = len * 2;
7488
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007489 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007490 if (buffer == NULL) {
7491 XP_ERROR0(XPATH_MEMORY_ERROR);
7492 }
7493 memcpy(buffer, buf, len);
7494 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7495 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007496 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007497 (IS_COMBINING(c)) ||
7498 (IS_EXTENDER(c))) {
7499 if (len + 10 > max) {
7500 max *= 2;
7501 buffer = (xmlChar *) xmlRealloc(buffer,
7502 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007503 if (buffer == NULL) {
7504 XP_ERROR0(XPATH_MEMORY_ERROR);
7505 }
7506 }
7507 COPY_BUF(l,buffer,len,c);
7508 NEXTL(l);
7509 c = CUR_CHAR(l);
7510 }
7511 buffer[len] = 0;
7512 return(buffer);
7513 }
7514 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007515 if (len == 0)
7516 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007517 return(xmlStrndup(buf, len));
7518}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007519
7520#define MAX_FRAC 20
7521
William M. Brack372a4452004-02-17 13:09:23 +00007522/*
7523 * These are used as divisors for the fractional part of a number.
7524 * Since the table includes 1.0 (representing '0' fractional digits),
7525 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
7526 */
7527static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007528 1.0, 10.0, 100.0, 1000.0, 10000.0,
7529 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7530 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7531 100000000000000.0,
7532 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00007533 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00007534};
7535
Owen Taylor3473f882001-02-23 17:55:21 +00007536/**
7537 * xmlXPathStringEvalNumber:
7538 * @str: A string to scan
7539 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007540 * [30a] Float ::= Number ('e' Digits?)?
7541 *
Owen Taylor3473f882001-02-23 17:55:21 +00007542 * [30] Number ::= Digits ('.' Digits?)?
7543 * | '.' Digits
7544 * [31] Digits ::= [0-9]+
7545 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007546 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007547 * In complement of the Number expression, this function also handles
7548 * negative values : '-' Number.
7549 *
7550 * Returns the double value.
7551 */
7552double
7553xmlXPathStringEvalNumber(const xmlChar *str) {
7554 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007555 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007556 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007557 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007558 int exponent = 0;
7559 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007560#ifdef __GNUC__
7561 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007562 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007563#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007564 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007565 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007566 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7567 return(xmlXPathNAN);
7568 }
7569 if (*cur == '-') {
7570 isneg = 1;
7571 cur++;
7572 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007573
7574#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007575 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007576 * tmp/temp is a workaround against a gcc compiler bug
7577 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007578 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007579 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007580 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007581 ret = ret * 10;
7582 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007583 ok = 1;
7584 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007585 temp = (double) tmp;
7586 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007587 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007588#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007589 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007590 while ((*cur >= '0') && (*cur <= '9')) {
7591 ret = ret * 10 + (*cur - '0');
7592 ok = 1;
7593 cur++;
7594 }
7595#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007596
Owen Taylor3473f882001-02-23 17:55:21 +00007597 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007598 int v, frac = 0;
7599 double fraction = 0;
7600
Owen Taylor3473f882001-02-23 17:55:21 +00007601 cur++;
7602 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7603 return(xmlXPathNAN);
7604 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007605 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7606 v = (*cur - '0');
7607 fraction = fraction * 10 + v;
7608 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007609 cur++;
7610 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007611 fraction /= my_pow10[frac];
7612 ret = ret + fraction;
7613 while ((*cur >= '0') && (*cur <= '9'))
7614 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007615 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007616 if ((*cur == 'e') || (*cur == 'E')) {
7617 cur++;
7618 if (*cur == '-') {
7619 is_exponent_negative = 1;
7620 cur++;
William M. Brack99127052004-05-24 02:52:28 +00007621 } else if (*cur == '+') {
7622 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007623 }
7624 while ((*cur >= '0') && (*cur <= '9')) {
7625 exponent = exponent * 10 + (*cur - '0');
7626 cur++;
7627 }
7628 }
William M. Brack76e95df2003-10-18 16:20:14 +00007629 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007630 if (*cur != 0) return(xmlXPathNAN);
7631 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007632 if (is_exponent_negative) exponent = -exponent;
7633 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007634 return(ret);
7635}
7636
7637/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007638 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007639 * @ctxt: the XPath Parser context
7640 *
7641 * [30] Number ::= Digits ('.' Digits?)?
7642 * | '.' Digits
7643 * [31] Digits ::= [0-9]+
7644 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007645 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007646 *
7647 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007648static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007649xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7650{
Owen Taylor3473f882001-02-23 17:55:21 +00007651 double ret = 0.0;
7652 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007653 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007654 int exponent = 0;
7655 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007656#ifdef __GNUC__
7657 unsigned long tmp = 0;
7658 double temp;
7659#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007660
7661 CHECK_ERROR;
7662 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7663 XP_ERROR(XPATH_NUMBER_ERROR);
7664 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007665#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007666 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007667 * tmp/temp is a workaround against a gcc compiler bug
7668 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007669 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007670 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007671 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007672 ret = ret * 10;
7673 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007674 ok = 1;
7675 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007676 temp = (double) tmp;
7677 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007678 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007679#else
7680 ret = 0;
7681 while ((CUR >= '0') && (CUR <= '9')) {
7682 ret = ret * 10 + (CUR - '0');
7683 ok = 1;
7684 NEXT;
7685 }
7686#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007687 if (CUR == '.') {
7688 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007689 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7690 XP_ERROR(XPATH_NUMBER_ERROR);
7691 }
7692 while ((CUR >= '0') && (CUR <= '9')) {
7693 mult /= 10;
7694 ret = ret + (CUR - '0') * mult;
7695 NEXT;
7696 }
Owen Taylor3473f882001-02-23 17:55:21 +00007697 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007698 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007699 NEXT;
7700 if (CUR == '-') {
7701 is_exponent_negative = 1;
7702 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00007703 } else if (CUR == '+') {
7704 NEXT;
7705 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007706 while ((CUR >= '0') && (CUR <= '9')) {
7707 exponent = exponent * 10 + (CUR - '0');
7708 NEXT;
7709 }
7710 if (is_exponent_negative)
7711 exponent = -exponent;
7712 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007713 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007714 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007715 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007716}
7717
7718/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007719 * xmlXPathParseLiteral:
7720 * @ctxt: the XPath Parser context
7721 *
7722 * Parse a Literal
7723 *
7724 * [29] Literal ::= '"' [^"]* '"'
7725 * | "'" [^']* "'"
7726 *
7727 * Returns the value found or NULL in case of error
7728 */
7729static xmlChar *
7730xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7731 const xmlChar *q;
7732 xmlChar *ret = NULL;
7733
7734 if (CUR == '"') {
7735 NEXT;
7736 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007737 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007738 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007739 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007740 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7741 } else {
7742 ret = xmlStrndup(q, CUR_PTR - q);
7743 NEXT;
7744 }
7745 } else if (CUR == '\'') {
7746 NEXT;
7747 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007748 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007749 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007750 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007751 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7752 } else {
7753 ret = xmlStrndup(q, CUR_PTR - q);
7754 NEXT;
7755 }
7756 } else {
7757 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7758 }
7759 return(ret);
7760}
7761
7762/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007763 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007764 * @ctxt: the XPath Parser context
7765 *
7766 * Parse a Literal and push it on the stack.
7767 *
7768 * [29] Literal ::= '"' [^"]* '"'
7769 * | "'" [^']* "'"
7770 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007771 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007772 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007773static void
7774xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007775 const xmlChar *q;
7776 xmlChar *ret = NULL;
7777
7778 if (CUR == '"') {
7779 NEXT;
7780 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007781 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007782 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007783 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007784 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7785 } else {
7786 ret = xmlStrndup(q, CUR_PTR - q);
7787 NEXT;
7788 }
7789 } else if (CUR == '\'') {
7790 NEXT;
7791 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007792 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007793 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007794 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007795 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7796 } else {
7797 ret = xmlStrndup(q, CUR_PTR - q);
7798 NEXT;
7799 }
7800 } else {
7801 XP_ERROR(XPATH_START_LITERAL_ERROR);
7802 }
7803 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007804 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7805 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007806 xmlFree(ret);
7807}
7808
7809/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007810 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007811 * @ctxt: the XPath Parser context
7812 *
7813 * Parse a VariableReference, evaluate it and push it on the stack.
7814 *
7815 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00007816 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00007817 * of any of the types that are possible for the value of an expression,
7818 * and may also be of additional types not specified here.
7819 *
7820 * Early evaluation is possible since:
7821 * The variable bindings [...] used to evaluate a subexpression are
7822 * always the same as those used to evaluate the containing expression.
7823 *
7824 * [36] VariableReference ::= '$' QName
7825 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007826static void
7827xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007828 xmlChar *name;
7829 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007830
7831 SKIP_BLANKS;
7832 if (CUR != '$') {
7833 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7834 }
7835 NEXT;
7836 name = xmlXPathParseQName(ctxt, &prefix);
7837 if (name == NULL) {
7838 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7839 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007840 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007841 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7842 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007843 SKIP_BLANKS;
7844}
7845
7846/**
7847 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007848 * @name: a name string
7849 *
7850 * Is the name given a NodeType one.
7851 *
7852 * [38] NodeType ::= 'comment'
7853 * | 'text'
7854 * | 'processing-instruction'
7855 * | 'node'
7856 *
7857 * Returns 1 if true 0 otherwise
7858 */
7859int
7860xmlXPathIsNodeType(const xmlChar *name) {
7861 if (name == NULL)
7862 return(0);
7863
Daniel Veillard1971ee22002-01-31 20:29:19 +00007864 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007865 return(1);
7866 if (xmlStrEqual(name, BAD_CAST "text"))
7867 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007868 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007869 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007870 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007871 return(1);
7872 return(0);
7873}
7874
7875/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007876 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007877 * @ctxt: the XPath Parser context
7878 *
7879 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7880 * [17] Argument ::= Expr
7881 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007882 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007883 * pushed on the stack
7884 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007885static void
7886xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007887 xmlChar *name;
7888 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007889 int nbargs = 0;
7890
7891 name = xmlXPathParseQName(ctxt, &prefix);
7892 if (name == NULL) {
7893 XP_ERROR(XPATH_EXPR_ERROR);
7894 }
7895 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007896#ifdef DEBUG_EXPR
7897 if (prefix == NULL)
7898 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7899 name);
7900 else
7901 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7902 prefix, name);
7903#endif
7904
Owen Taylor3473f882001-02-23 17:55:21 +00007905 if (CUR != '(') {
7906 XP_ERROR(XPATH_EXPR_ERROR);
7907 }
7908 NEXT;
7909 SKIP_BLANKS;
7910
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007911 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007912 if (CUR != ')') {
7913 while (CUR != 0) {
7914 int op1 = ctxt->comp->last;
7915 ctxt->comp->last = -1;
7916 xmlXPathCompileExpr(ctxt);
7917 CHECK_ERROR;
7918 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7919 nbargs++;
7920 if (CUR == ')') break;
7921 if (CUR != ',') {
7922 XP_ERROR(XPATH_EXPR_ERROR);
7923 }
7924 NEXT;
7925 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007926 }
Owen Taylor3473f882001-02-23 17:55:21 +00007927 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007928 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7929 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007930 NEXT;
7931 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007932}
7933
7934/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007935 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007936 * @ctxt: the XPath Parser context
7937 *
7938 * [15] PrimaryExpr ::= VariableReference
7939 * | '(' Expr ')'
7940 * | Literal
7941 * | Number
7942 * | FunctionCall
7943 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007944 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007945 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007946static void
7947xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007948 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007949 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007950 else if (CUR == '(') {
7951 NEXT;
7952 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007953 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007954 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007955 if (CUR != ')') {
7956 XP_ERROR(XPATH_EXPR_ERROR);
7957 }
7958 NEXT;
7959 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00007960 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007961 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007962 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007963 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007964 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007965 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007966 }
7967 SKIP_BLANKS;
7968}
7969
7970/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007971 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007972 * @ctxt: the XPath Parser context
7973 *
7974 * [20] FilterExpr ::= PrimaryExpr
7975 * | FilterExpr Predicate
7976 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007977 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007978 * Square brackets are used to filter expressions in the same way that
7979 * they are used in location paths. It is an error if the expression to
7980 * be filtered does not evaluate to a node-set. The context node list
7981 * used for evaluating the expression in square brackets is the node-set
7982 * to be filtered listed in document order.
7983 */
7984
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007985static void
7986xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7987 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007988 CHECK_ERROR;
7989 SKIP_BLANKS;
7990
7991 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007992 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007993 SKIP_BLANKS;
7994 }
7995
7996
7997}
7998
7999/**
8000 * xmlXPathScanName:
8001 * @ctxt: the XPath Parser context
8002 *
8003 * Trickery: parse an XML name but without consuming the input flow
8004 * Needed to avoid insanity in the parser state.
8005 *
8006 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8007 * CombiningChar | Extender
8008 *
8009 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8010 *
8011 * [6] Names ::= Name (S Name)*
8012 *
8013 * Returns the Name parsed or NULL
8014 */
8015
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008016static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00008017xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +00008018 int len = 0, l;
8019 int c;
Daniel Veillard03226812004-11-01 14:55:21 +00008020 const xmlChar *cur;
8021 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00008022
Daniel Veillard03226812004-11-01 14:55:21 +00008023 cur = ctxt->cur;
8024
8025 c = CUR_CHAR(l);
8026 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8027 (!IS_LETTER(c) && (c != '_') &&
8028 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008029 return(NULL);
8030 }
8031
Daniel Veillard03226812004-11-01 14:55:21 +00008032 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8033 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8034 (c == '.') || (c == '-') ||
8035 (c == '_') || (c == ':') ||
8036 (IS_COMBINING(c)) ||
8037 (IS_EXTENDER(c)))) {
8038 len += l;
8039 NEXTL(l);
8040 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +00008041 }
Daniel Veillard03226812004-11-01 14:55:21 +00008042 ret = xmlStrndup(cur, ctxt->cur - cur);
8043 ctxt->cur = cur;
8044 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00008045}
8046
8047/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008048 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008049 * @ctxt: the XPath Parser context
8050 *
8051 * [19] PathExpr ::= LocationPath
8052 * | FilterExpr
8053 * | FilterExpr '/' RelativeLocationPath
8054 * | FilterExpr '//' RelativeLocationPath
8055 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008056 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008057 * The / operator and // operators combine an arbitrary expression
8058 * and a relative location path. It is an error if the expression
8059 * does not evaluate to a node-set.
8060 * The / operator does composition in the same way as when / is
8061 * used in a location path. As in location paths, // is short for
8062 * /descendant-or-self::node()/.
8063 */
8064
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008065static void
8066xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008067 int lc = 1; /* Should we branch to LocationPath ? */
8068 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8069
8070 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008071 if ((CUR == '$') || (CUR == '(') ||
8072 (IS_ASCII_DIGIT(CUR)) ||
8073 (CUR == '\'') || (CUR == '"') ||
8074 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008075 lc = 0;
8076 } else if (CUR == '*') {
8077 /* relative or absolute location path */
8078 lc = 1;
8079 } else if (CUR == '/') {
8080 /* relative or absolute location path */
8081 lc = 1;
8082 } else if (CUR == '@') {
8083 /* relative abbreviated attribute location path */
8084 lc = 1;
8085 } else if (CUR == '.') {
8086 /* relative abbreviated attribute location path */
8087 lc = 1;
8088 } else {
8089 /*
8090 * Problem is finding if we have a name here whether it's:
8091 * - a nodetype
8092 * - a function call in which case it's followed by '('
8093 * - an axis in which case it's followed by ':'
8094 * - a element name
8095 * We do an a priori analysis here rather than having to
8096 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008097 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008098 * read/write/debug.
8099 */
8100 SKIP_BLANKS;
8101 name = xmlXPathScanName(ctxt);
8102 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8103#ifdef DEBUG_STEP
8104 xmlGenericError(xmlGenericErrorContext,
8105 "PathExpr: Axis\n");
8106#endif
8107 lc = 1;
8108 xmlFree(name);
8109 } else if (name != NULL) {
8110 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008111
8112
8113 while (NXT(len) != 0) {
8114 if (NXT(len) == '/') {
8115 /* element name */
8116#ifdef DEBUG_STEP
8117 xmlGenericError(xmlGenericErrorContext,
8118 "PathExpr: AbbrRelLocation\n");
8119#endif
8120 lc = 1;
8121 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008122 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008123 /* ignore blanks */
8124 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008125 } else if (NXT(len) == ':') {
8126#ifdef DEBUG_STEP
8127 xmlGenericError(xmlGenericErrorContext,
8128 "PathExpr: AbbrRelLocation\n");
8129#endif
8130 lc = 1;
8131 break;
8132 } else if ((NXT(len) == '(')) {
8133 /* Note Type or Function */
8134 if (xmlXPathIsNodeType(name)) {
8135#ifdef DEBUG_STEP
8136 xmlGenericError(xmlGenericErrorContext,
8137 "PathExpr: Type search\n");
8138#endif
8139 lc = 1;
8140 } else {
8141#ifdef DEBUG_STEP
8142 xmlGenericError(xmlGenericErrorContext,
8143 "PathExpr: function call\n");
8144#endif
8145 lc = 0;
8146 }
8147 break;
8148 } else if ((NXT(len) == '[')) {
8149 /* element name */
8150#ifdef DEBUG_STEP
8151 xmlGenericError(xmlGenericErrorContext,
8152 "PathExpr: AbbrRelLocation\n");
8153#endif
8154 lc = 1;
8155 break;
8156 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8157 (NXT(len) == '=')) {
8158 lc = 1;
8159 break;
8160 } else {
8161 lc = 1;
8162 break;
8163 }
8164 len++;
8165 }
8166 if (NXT(len) == 0) {
8167#ifdef DEBUG_STEP
8168 xmlGenericError(xmlGenericErrorContext,
8169 "PathExpr: AbbrRelLocation\n");
8170#endif
8171 /* element name */
8172 lc = 1;
8173 }
8174 xmlFree(name);
8175 } else {
William M. Brack08171912003-12-29 02:52:11 +00008176 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008177 XP_ERROR(XPATH_EXPR_ERROR);
8178 }
8179 }
8180
8181 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008182 if (CUR == '/') {
8183 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8184 } else {
8185 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008186 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008187 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008188 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008189 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008190 CHECK_ERROR;
8191 if ((CUR == '/') && (NXT(1) == '/')) {
8192 SKIP(2);
8193 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008194
8195 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8196 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8197 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8198
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008199 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008200 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008201 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008202 }
8203 }
8204 SKIP_BLANKS;
8205}
8206
8207/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008208 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008209 * @ctxt: the XPath Parser context
8210 *
8211 * [18] UnionExpr ::= PathExpr
8212 * | UnionExpr '|' PathExpr
8213 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008214 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008215 */
8216
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008217static void
8218xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8219 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008220 CHECK_ERROR;
8221 SKIP_BLANKS;
8222 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008223 int op1 = ctxt->comp->last;
8224 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008225
8226 NEXT;
8227 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008228 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008229
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008230 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8231
Owen Taylor3473f882001-02-23 17:55:21 +00008232 SKIP_BLANKS;
8233 }
Owen Taylor3473f882001-02-23 17:55:21 +00008234}
8235
8236/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008237 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008238 * @ctxt: the XPath Parser context
8239 *
8240 * [27] UnaryExpr ::= UnionExpr
8241 * | '-' UnaryExpr
8242 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008243 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008244 */
8245
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008246static void
8247xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008248 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008249 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008250
8251 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008252 while (CUR == '-') {
8253 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008254 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008255 NEXT;
8256 SKIP_BLANKS;
8257 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008258
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008259 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008260 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008261 if (found) {
8262 if (minus)
8263 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8264 else
8265 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008266 }
8267}
8268
8269/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008270 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008271 * @ctxt: the XPath Parser context
8272 *
8273 * [26] MultiplicativeExpr ::= UnaryExpr
8274 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8275 * | MultiplicativeExpr 'div' UnaryExpr
8276 * | MultiplicativeExpr 'mod' UnaryExpr
8277 * [34] MultiplyOperator ::= '*'
8278 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008279 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008280 */
8281
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008282static void
8283xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8284 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008285 CHECK_ERROR;
8286 SKIP_BLANKS;
8287 while ((CUR == '*') ||
8288 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8289 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8290 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008291 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008292
8293 if (CUR == '*') {
8294 op = 0;
8295 NEXT;
8296 } else if (CUR == 'd') {
8297 op = 1;
8298 SKIP(3);
8299 } else if (CUR == 'm') {
8300 op = 2;
8301 SKIP(3);
8302 }
8303 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008304 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008305 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008306 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008307 SKIP_BLANKS;
8308 }
8309}
8310
8311/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008312 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008313 * @ctxt: the XPath Parser context
8314 *
8315 * [25] AdditiveExpr ::= MultiplicativeExpr
8316 * | AdditiveExpr '+' MultiplicativeExpr
8317 * | AdditiveExpr '-' MultiplicativeExpr
8318 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008319 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008320 */
8321
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008322static void
8323xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008324
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008325 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008326 CHECK_ERROR;
8327 SKIP_BLANKS;
8328 while ((CUR == '+') || (CUR == '-')) {
8329 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008330 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008331
8332 if (CUR == '+') plus = 1;
8333 else plus = 0;
8334 NEXT;
8335 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008336 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008337 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008338 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008339 SKIP_BLANKS;
8340 }
8341}
8342
8343/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008344 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008345 * @ctxt: the XPath Parser context
8346 *
8347 * [24] RelationalExpr ::= AdditiveExpr
8348 * | RelationalExpr '<' AdditiveExpr
8349 * | RelationalExpr '>' AdditiveExpr
8350 * | RelationalExpr '<=' AdditiveExpr
8351 * | RelationalExpr '>=' AdditiveExpr
8352 *
8353 * A <= B > C is allowed ? Answer from James, yes with
8354 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8355 * which is basically what got implemented.
8356 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008357 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008358 * on the stack
8359 */
8360
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008361static void
8362xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8363 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008364 CHECK_ERROR;
8365 SKIP_BLANKS;
8366 while ((CUR == '<') ||
8367 (CUR == '>') ||
8368 ((CUR == '<') && (NXT(1) == '=')) ||
8369 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008370 int inf, strict;
8371 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008372
8373 if (CUR == '<') inf = 1;
8374 else inf = 0;
8375 if (NXT(1) == '=') strict = 0;
8376 else strict = 1;
8377 NEXT;
8378 if (!strict) NEXT;
8379 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008380 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008381 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008382 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008383 SKIP_BLANKS;
8384 }
8385}
8386
8387/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008388 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008389 * @ctxt: the XPath Parser context
8390 *
8391 * [23] EqualityExpr ::= RelationalExpr
8392 * | EqualityExpr '=' RelationalExpr
8393 * | EqualityExpr '!=' RelationalExpr
8394 *
8395 * A != B != C is allowed ? Answer from James, yes with
8396 * (RelationalExpr = RelationalExpr) = RelationalExpr
8397 * (RelationalExpr != RelationalExpr) != RelationalExpr
8398 * which is basically what got implemented.
8399 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008400 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008401 *
8402 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008403static void
8404xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8405 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008406 CHECK_ERROR;
8407 SKIP_BLANKS;
8408 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008409 int eq;
8410 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008411
8412 if (CUR == '=') eq = 1;
8413 else eq = 0;
8414 NEXT;
8415 if (!eq) NEXT;
8416 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008417 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008418 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008419 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008420 SKIP_BLANKS;
8421 }
8422}
8423
8424/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008425 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008426 * @ctxt: the XPath Parser context
8427 *
8428 * [22] AndExpr ::= EqualityExpr
8429 * | AndExpr 'and' EqualityExpr
8430 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008431 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008432 *
8433 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008434static void
8435xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8436 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008437 CHECK_ERROR;
8438 SKIP_BLANKS;
8439 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008440 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008441 SKIP(3);
8442 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008443 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008444 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008445 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008446 SKIP_BLANKS;
8447 }
8448}
8449
8450/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008451 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008452 * @ctxt: the XPath Parser context
8453 *
8454 * [14] Expr ::= OrExpr
8455 * [21] OrExpr ::= AndExpr
8456 * | OrExpr 'or' AndExpr
8457 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008458 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008459 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008460static void
8461xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8462 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008463 CHECK_ERROR;
8464 SKIP_BLANKS;
8465 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008466 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008467 SKIP(2);
8468 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008469 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008470 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008471 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8472 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008473 SKIP_BLANKS;
8474 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008475 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8476 /* more ops could be optimized too */
8477 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8478 }
Owen Taylor3473f882001-02-23 17:55:21 +00008479}
8480
8481/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008482 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008483 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008484 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008485 *
8486 * [8] Predicate ::= '[' PredicateExpr ']'
8487 * [9] PredicateExpr ::= Expr
8488 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008489 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008490 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008491static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008492xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008493 int op1 = ctxt->comp->last;
8494
8495 SKIP_BLANKS;
8496 if (CUR != '[') {
8497 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8498 }
8499 NEXT;
8500 SKIP_BLANKS;
8501
8502 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008503 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008504 CHECK_ERROR;
8505
8506 if (CUR != ']') {
8507 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8508 }
8509
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008510 if (filter)
8511 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8512 else
8513 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008514
8515 NEXT;
8516 SKIP_BLANKS;
8517}
8518
8519/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008520 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008521 * @ctxt: the XPath Parser context
8522 * @test: pointer to a xmlXPathTestVal
8523 * @type: pointer to a xmlXPathTypeVal
8524 * @prefix: placeholder for a possible name prefix
8525 *
8526 * [7] NodeTest ::= NameTest
8527 * | NodeType '(' ')'
8528 * | 'processing-instruction' '(' Literal ')'
8529 *
8530 * [37] NameTest ::= '*'
8531 * | NCName ':' '*'
8532 * | QName
8533 * [38] NodeType ::= 'comment'
8534 * | 'text'
8535 * | 'processing-instruction'
8536 * | 'node'
8537 *
William M. Brack08171912003-12-29 02:52:11 +00008538 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00008539 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008540static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008541xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8542 xmlXPathTypeVal *type, const xmlChar **prefix,
8543 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008544 int blanks;
8545
8546 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8547 STRANGE;
8548 return(NULL);
8549 }
William M. Brack78637da2003-07-31 14:47:38 +00008550 *type = (xmlXPathTypeVal) 0;
8551 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008552 *prefix = NULL;
8553 SKIP_BLANKS;
8554
8555 if ((name == NULL) && (CUR == '*')) {
8556 /*
8557 * All elements
8558 */
8559 NEXT;
8560 *test = NODE_TEST_ALL;
8561 return(NULL);
8562 }
8563
8564 if (name == NULL)
8565 name = xmlXPathParseNCName(ctxt);
8566 if (name == NULL) {
8567 XP_ERROR0(XPATH_EXPR_ERROR);
8568 }
8569
William M. Brack76e95df2003-10-18 16:20:14 +00008570 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008571 SKIP_BLANKS;
8572 if (CUR == '(') {
8573 NEXT;
8574 /*
8575 * NodeType or PI search
8576 */
8577 if (xmlStrEqual(name, BAD_CAST "comment"))
8578 *type = NODE_TYPE_COMMENT;
8579 else if (xmlStrEqual(name, BAD_CAST "node"))
8580 *type = NODE_TYPE_NODE;
8581 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8582 *type = NODE_TYPE_PI;
8583 else if (xmlStrEqual(name, BAD_CAST "text"))
8584 *type = NODE_TYPE_TEXT;
8585 else {
8586 if (name != NULL)
8587 xmlFree(name);
8588 XP_ERROR0(XPATH_EXPR_ERROR);
8589 }
8590
8591 *test = NODE_TEST_TYPE;
8592
8593 SKIP_BLANKS;
8594 if (*type == NODE_TYPE_PI) {
8595 /*
8596 * Specific case: search a PI by name.
8597 */
Owen Taylor3473f882001-02-23 17:55:21 +00008598 if (name != NULL)
8599 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008600 name = NULL;
8601 if (CUR != ')') {
8602 name = xmlXPathParseLiteral(ctxt);
8603 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008604 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008605 SKIP_BLANKS;
8606 }
Owen Taylor3473f882001-02-23 17:55:21 +00008607 }
8608 if (CUR != ')') {
8609 if (name != NULL)
8610 xmlFree(name);
8611 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8612 }
8613 NEXT;
8614 return(name);
8615 }
8616 *test = NODE_TEST_NAME;
8617 if ((!blanks) && (CUR == ':')) {
8618 NEXT;
8619
8620 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008621 * Since currently the parser context don't have a
8622 * namespace list associated:
8623 * The namespace name for this prefix can be computed
8624 * only at evaluation time. The compilation is done
8625 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008626 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008627#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008628 *prefix = xmlXPathNsLookup(ctxt->context, name);
8629 if (name != NULL)
8630 xmlFree(name);
8631 if (*prefix == NULL) {
8632 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8633 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008634#else
8635 *prefix = name;
8636#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008637
8638 if (CUR == '*') {
8639 /*
8640 * All elements
8641 */
8642 NEXT;
8643 *test = NODE_TEST_ALL;
8644 return(NULL);
8645 }
8646
8647 name = xmlXPathParseNCName(ctxt);
8648 if (name == NULL) {
8649 XP_ERROR0(XPATH_EXPR_ERROR);
8650 }
8651 }
8652 return(name);
8653}
8654
8655/**
8656 * xmlXPathIsAxisName:
8657 * @name: a preparsed name token
8658 *
8659 * [6] AxisName ::= 'ancestor'
8660 * | 'ancestor-or-self'
8661 * | 'attribute'
8662 * | 'child'
8663 * | 'descendant'
8664 * | 'descendant-or-self'
8665 * | 'following'
8666 * | 'following-sibling'
8667 * | 'namespace'
8668 * | 'parent'
8669 * | 'preceding'
8670 * | 'preceding-sibling'
8671 * | 'self'
8672 *
8673 * Returns the axis or 0
8674 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008675static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008676xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008677 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008678 switch (name[0]) {
8679 case 'a':
8680 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8681 ret = AXIS_ANCESTOR;
8682 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8683 ret = AXIS_ANCESTOR_OR_SELF;
8684 if (xmlStrEqual(name, BAD_CAST "attribute"))
8685 ret = AXIS_ATTRIBUTE;
8686 break;
8687 case 'c':
8688 if (xmlStrEqual(name, BAD_CAST "child"))
8689 ret = AXIS_CHILD;
8690 break;
8691 case 'd':
8692 if (xmlStrEqual(name, BAD_CAST "descendant"))
8693 ret = AXIS_DESCENDANT;
8694 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8695 ret = AXIS_DESCENDANT_OR_SELF;
8696 break;
8697 case 'f':
8698 if (xmlStrEqual(name, BAD_CAST "following"))
8699 ret = AXIS_FOLLOWING;
8700 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8701 ret = AXIS_FOLLOWING_SIBLING;
8702 break;
8703 case 'n':
8704 if (xmlStrEqual(name, BAD_CAST "namespace"))
8705 ret = AXIS_NAMESPACE;
8706 break;
8707 case 'p':
8708 if (xmlStrEqual(name, BAD_CAST "parent"))
8709 ret = AXIS_PARENT;
8710 if (xmlStrEqual(name, BAD_CAST "preceding"))
8711 ret = AXIS_PRECEDING;
8712 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8713 ret = AXIS_PRECEDING_SIBLING;
8714 break;
8715 case 's':
8716 if (xmlStrEqual(name, BAD_CAST "self"))
8717 ret = AXIS_SELF;
8718 break;
8719 }
8720 return(ret);
8721}
8722
8723/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008724 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008725 * @ctxt: the XPath Parser context
8726 *
8727 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8728 * | AbbreviatedStep
8729 *
8730 * [12] AbbreviatedStep ::= '.' | '..'
8731 *
8732 * [5] AxisSpecifier ::= AxisName '::'
8733 * | AbbreviatedAxisSpecifier
8734 *
8735 * [13] AbbreviatedAxisSpecifier ::= '@'?
8736 *
8737 * Modified for XPtr range support as:
8738 *
8739 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8740 * | AbbreviatedStep
8741 * | 'range-to' '(' Expr ')' Predicate*
8742 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008743 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008744 * A location step of . is short for self::node(). This is
8745 * particularly useful in conjunction with //. For example, the
8746 * location path .//para is short for
8747 * self::node()/descendant-or-self::node()/child::para
8748 * and so will select all para descendant elements of the context
8749 * node.
8750 * Similarly, a location step of .. is short for parent::node().
8751 * For example, ../title is short for parent::node()/child::title
8752 * and so will select the title children of the parent of the context
8753 * node.
8754 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008755static void
8756xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008757#ifdef LIBXML_XPTR_ENABLED
8758 int rangeto = 0;
8759 int op2 = -1;
8760#endif
8761
Owen Taylor3473f882001-02-23 17:55:21 +00008762 SKIP_BLANKS;
8763 if ((CUR == '.') && (NXT(1) == '.')) {
8764 SKIP(2);
8765 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008766 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8767 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008768 } else if (CUR == '.') {
8769 NEXT;
8770 SKIP_BLANKS;
8771 } else {
8772 xmlChar *name = NULL;
8773 const xmlChar *prefix = NULL;
8774 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008775 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008776 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008777 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008778
8779 /*
8780 * The modification needed for XPointer change to the production
8781 */
8782#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008783 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008784 name = xmlXPathParseNCName(ctxt);
8785 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008786 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008787 xmlFree(name);
8788 SKIP_BLANKS;
8789 if (CUR != '(') {
8790 XP_ERROR(XPATH_EXPR_ERROR);
8791 }
8792 NEXT;
8793 SKIP_BLANKS;
8794
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008795 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008796 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008797 CHECK_ERROR;
8798
8799 SKIP_BLANKS;
8800 if (CUR != ')') {
8801 XP_ERROR(XPATH_EXPR_ERROR);
8802 }
8803 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008804 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008805 goto eval_predicates;
8806 }
8807 }
8808#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008809 if (CUR == '*') {
8810 axis = AXIS_CHILD;
8811 } else {
8812 if (name == NULL)
8813 name = xmlXPathParseNCName(ctxt);
8814 if (name != NULL) {
8815 axis = xmlXPathIsAxisName(name);
8816 if (axis != 0) {
8817 SKIP_BLANKS;
8818 if ((CUR == ':') && (NXT(1) == ':')) {
8819 SKIP(2);
8820 xmlFree(name);
8821 name = NULL;
8822 } else {
8823 /* an element name can conflict with an axis one :-\ */
8824 axis = AXIS_CHILD;
8825 }
Owen Taylor3473f882001-02-23 17:55:21 +00008826 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008827 axis = AXIS_CHILD;
8828 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008829 } else if (CUR == '@') {
8830 NEXT;
8831 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008832 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008833 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008834 }
Owen Taylor3473f882001-02-23 17:55:21 +00008835 }
8836
8837 CHECK_ERROR;
8838
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008839 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008840 if (test == 0)
8841 return;
8842
8843#ifdef DEBUG_STEP
8844 xmlGenericError(xmlGenericErrorContext,
8845 "Basis : computing new set\n");
8846#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008847
Owen Taylor3473f882001-02-23 17:55:21 +00008848#ifdef DEBUG_STEP
8849 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008850 if (ctxt->value == NULL)
8851 xmlGenericError(xmlGenericErrorContext, "no value\n");
8852 else if (ctxt->value->nodesetval == NULL)
8853 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8854 else
8855 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008856#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008857
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008858#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008859eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008860#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008861 op1 = ctxt->comp->last;
8862 ctxt->comp->last = -1;
8863
Owen Taylor3473f882001-02-23 17:55:21 +00008864 SKIP_BLANKS;
8865 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008866 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008867 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008868
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008869#ifdef LIBXML_XPTR_ENABLED
8870 if (rangeto) {
8871 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8872 } else
8873#endif
8874 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8875 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008876
Owen Taylor3473f882001-02-23 17:55:21 +00008877 }
8878#ifdef DEBUG_STEP
8879 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008880 if (ctxt->value == NULL)
8881 xmlGenericError(xmlGenericErrorContext, "no value\n");
8882 else if (ctxt->value->nodesetval == NULL)
8883 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8884 else
8885 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8886 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008887#endif
8888}
8889
8890/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008891 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008892 * @ctxt: the XPath Parser context
8893 *
8894 * [3] RelativeLocationPath ::= Step
8895 * | RelativeLocationPath '/' Step
8896 * | AbbreviatedRelativeLocationPath
8897 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8898 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008899 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008900 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008901static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008902xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008903(xmlXPathParserContextPtr ctxt) {
8904 SKIP_BLANKS;
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,
8909 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008910 } else if (CUR == '/') {
8911 NEXT;
8912 SKIP_BLANKS;
8913 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008914 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008915 SKIP_BLANKS;
8916 while (CUR == '/') {
8917 if ((CUR == '/') && (NXT(1) == '/')) {
8918 SKIP(2);
8919 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008920 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008921 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008922 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008923 } else if (CUR == '/') {
8924 NEXT;
8925 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008926 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008927 }
8928 SKIP_BLANKS;
8929 }
8930}
8931
8932/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008933 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008934 * @ctxt: the XPath Parser context
8935 *
8936 * [1] LocationPath ::= RelativeLocationPath
8937 * | AbsoluteLocationPath
8938 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8939 * | AbbreviatedAbsoluteLocationPath
8940 * [10] AbbreviatedAbsoluteLocationPath ::=
8941 * '//' RelativeLocationPath
8942 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008943 * Compile a location path
8944 *
Owen Taylor3473f882001-02-23 17:55:21 +00008945 * // is short for /descendant-or-self::node()/. For example,
8946 * //para is short for /descendant-or-self::node()/child::para and
8947 * so will select any para element in the document (even a para element
8948 * that is a document element will be selected by //para since the
8949 * document element node is a child of the root node); div//para is
8950 * short for div/descendant-or-self::node()/child::para and so will
8951 * select all para descendants of div children.
8952 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008953static void
8954xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008955 SKIP_BLANKS;
8956 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008957 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008958 } else {
8959 while (CUR == '/') {
8960 if ((CUR == '/') && (NXT(1) == '/')) {
8961 SKIP(2);
8962 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008963 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8964 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008965 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008966 } else if (CUR == '/') {
8967 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008968 SKIP_BLANKS;
8969 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +00008970 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00008971 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008972 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008973 }
8974 }
8975 }
8976}
8977
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008978/************************************************************************
8979 * *
8980 * XPath precompiled expression evaluation *
8981 * *
8982 ************************************************************************/
8983
Daniel Veillardf06307e2001-07-03 10:35:50 +00008984static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008985xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8986
8987/**
8988 * xmlXPathNodeCollectAndTest:
8989 * @ctxt: the XPath Parser context
8990 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008991 * @first: pointer to the first element in document order
8992 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008993 *
8994 * This is the function implementing a step: based on the current list
8995 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00008996 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008997 *
8998 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008999 *
William M. Brack08171912003-12-29 02:52:11 +00009000 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009001 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009002static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009003xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009004 xmlXPathStepOpPtr op,
9005 xmlNodePtr * first, xmlNodePtr * last)
9006{
William M. Brack78637da2003-07-31 14:47:38 +00009007 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9008 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9009 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009010 const xmlChar *prefix = op->value4;
9011 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009012 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009013
9014#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009015 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009016#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009017 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009018 xmlNodeSetPtr ret, list;
9019 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009020 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00009021 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009022 xmlNodePtr cur = NULL;
9023 xmlXPathObjectPtr obj;
9024 xmlNodeSetPtr nodelist;
9025 xmlNodePtr tmp;
9026
Daniel Veillardf06307e2001-07-03 10:35:50 +00009027 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009028 obj = valuePop(ctxt);
9029 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009030 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009031 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009032 URI = xmlXPathNsLookup(ctxt->context, prefix);
9033 if (URI == NULL)
9034 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00009035 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009036#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009037 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009038#endif
9039 switch (axis) {
9040 case AXIS_ANCESTOR:
9041#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009042 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009043#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009044 first = NULL;
9045 next = xmlXPathNextAncestor;
9046 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009047 case AXIS_ANCESTOR_OR_SELF:
9048#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009049 xmlGenericError(xmlGenericErrorContext,
9050 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009051#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009052 first = NULL;
9053 next = xmlXPathNextAncestorOrSelf;
9054 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009055 case AXIS_ATTRIBUTE:
9056#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009057 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009058#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009059 first = NULL;
9060 last = NULL;
9061 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009062 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009063 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009064 case AXIS_CHILD:
9065#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009066 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009067#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009068 last = NULL;
9069 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009070 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009071 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009072 case AXIS_DESCENDANT:
9073#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009074 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009075#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009076 last = NULL;
9077 next = xmlXPathNextDescendant;
9078 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009079 case AXIS_DESCENDANT_OR_SELF:
9080#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009081 xmlGenericError(xmlGenericErrorContext,
9082 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009083#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009084 last = NULL;
9085 next = xmlXPathNextDescendantOrSelf;
9086 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009087 case AXIS_FOLLOWING:
9088#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009089 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009090#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009091 last = NULL;
9092 next = xmlXPathNextFollowing;
9093 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009094 case AXIS_FOLLOWING_SIBLING:
9095#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009096 xmlGenericError(xmlGenericErrorContext,
9097 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009098#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009099 last = NULL;
9100 next = xmlXPathNextFollowingSibling;
9101 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009102 case AXIS_NAMESPACE:
9103#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009104 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009105#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009106 first = NULL;
9107 last = NULL;
9108 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009109 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009110 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009111 case AXIS_PARENT:
9112#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009113 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009114#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009115 first = NULL;
9116 next = xmlXPathNextParent;
9117 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009118 case AXIS_PRECEDING:
9119#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009120 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009121#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009122 first = NULL;
9123 next = xmlXPathNextPrecedingInternal;
9124 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009125 case AXIS_PRECEDING_SIBLING:
9126#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009127 xmlGenericError(xmlGenericErrorContext,
9128 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009129#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009130 first = NULL;
9131 next = xmlXPathNextPrecedingSibling;
9132 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009133 case AXIS_SELF:
9134#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009135 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009136#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009137 first = NULL;
9138 last = NULL;
9139 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009140 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009141 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009142 }
9143 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009144 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009145
9146 nodelist = obj->nodesetval;
9147 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009148 xmlXPathFreeObject(obj);
9149 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9150 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009151 }
9152 addNode = xmlXPathNodeSetAddUnique;
9153 ret = NULL;
9154#ifdef DEBUG_STEP
9155 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009156 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009157 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009158 case NODE_TEST_NONE:
9159 xmlGenericError(xmlGenericErrorContext,
9160 " searching for none !!!\n");
9161 break;
9162 case NODE_TEST_TYPE:
9163 xmlGenericError(xmlGenericErrorContext,
9164 " searching for type %d\n", type);
9165 break;
9166 case NODE_TEST_PI:
9167 xmlGenericError(xmlGenericErrorContext,
9168 " searching for PI !!!\n");
9169 break;
9170 case NODE_TEST_ALL:
9171 xmlGenericError(xmlGenericErrorContext,
9172 " searching for *\n");
9173 break;
9174 case NODE_TEST_NS:
9175 xmlGenericError(xmlGenericErrorContext,
9176 " searching for namespace %s\n",
9177 prefix);
9178 break;
9179 case NODE_TEST_NAME:
9180 xmlGenericError(xmlGenericErrorContext,
9181 " searching for name %s\n", name);
9182 if (prefix != NULL)
9183 xmlGenericError(xmlGenericErrorContext,
9184 " with namespace %s\n", prefix);
9185 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009186 }
9187 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9188#endif
9189 /*
9190 * 2.3 Node Tests
9191 * - For the attribute axis, the principal node type is attribute.
9192 * - For the namespace axis, the principal node type is namespace.
9193 * - For other axes, the principal node type is element.
9194 *
9195 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009196 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009197 * select all element children of the context node
9198 */
9199 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009200 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009201 ctxt->context->node = nodelist->nodeTab[i];
9202
Daniel Veillardf06307e2001-07-03 10:35:50 +00009203 cur = NULL;
9204 list = xmlXPathNodeSetCreate(NULL);
9205 do {
9206 cur = next(ctxt, cur);
9207 if (cur == NULL)
9208 break;
9209 if ((first != NULL) && (*first == cur))
9210 break;
9211 if (((t % 256) == 0) &&
9212 (first != NULL) && (*first != NULL) &&
9213 (xmlXPathCmpNodes(*first, cur) >= 0))
9214 break;
9215 if ((last != NULL) && (*last == cur))
9216 break;
9217 if (((t % 256) == 0) &&
9218 (last != NULL) && (*last != NULL) &&
9219 (xmlXPathCmpNodes(cur, *last) >= 0))
9220 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009221 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009222#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009223 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9224#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009225 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009226 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009227 ctxt->context->node = tmp;
9228 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009229 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009230 if ((cur->type == type) ||
9231 ((type == NODE_TYPE_NODE) &&
9232 ((cur->type == XML_DOCUMENT_NODE) ||
9233 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9234 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009235 (cur->type == XML_NAMESPACE_DECL) ||
9236 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009237 (cur->type == XML_PI_NODE) ||
9238 (cur->type == XML_COMMENT_NODE) ||
9239 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009240 (cur->type == XML_TEXT_NODE))) ||
9241 ((type == NODE_TYPE_TEXT) &&
9242 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009243#ifdef DEBUG_STEP
9244 n++;
9245#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009246 addNode(list, cur);
9247 }
9248 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009249 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009250 if (cur->type == XML_PI_NODE) {
9251 if ((name != NULL) &&
9252 (!xmlStrEqual(name, cur->name)))
9253 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009254#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009255 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009256#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009257 addNode(list, cur);
9258 }
9259 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009260 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009261 if (axis == AXIS_ATTRIBUTE) {
9262 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009263#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009264 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009265#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009266 addNode(list, cur);
9267 }
9268 } else if (axis == AXIS_NAMESPACE) {
9269 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009270#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009271 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009272#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009273 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9274 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009275 }
9276 } else {
9277 if (cur->type == XML_ELEMENT_NODE) {
9278 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009279#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009280 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009281#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009282 addNode(list, cur);
9283 } else if ((cur->ns != NULL) &&
9284 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009285#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009286 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009287#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009288 addNode(list, cur);
9289 }
9290 }
9291 }
9292 break;
9293 case NODE_TEST_NS:{
9294 TODO;
9295 break;
9296 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009297 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009298 switch (cur->type) {
9299 case XML_ELEMENT_NODE:
9300 if (xmlStrEqual(name, cur->name)) {
9301 if (prefix == NULL) {
9302 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009303#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009304 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009305#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009306 addNode(list, cur);
9307 }
9308 } else {
9309 if ((cur->ns != NULL) &&
9310 (xmlStrEqual(URI,
9311 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009312#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009313 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009314#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009315 addNode(list, cur);
9316 }
9317 }
9318 }
9319 break;
9320 case XML_ATTRIBUTE_NODE:{
9321 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009322
Daniel Veillardf06307e2001-07-03 10:35:50 +00009323 if (xmlStrEqual(name, attr->name)) {
9324 if (prefix == NULL) {
9325 if ((attr->ns == NULL) ||
9326 (attr->ns->prefix == NULL)) {
9327#ifdef DEBUG_STEP
9328 n++;
9329#endif
9330 addNode(list,
9331 (xmlNodePtr) attr);
9332 }
9333 } else {
9334 if ((attr->ns != NULL) &&
9335 (xmlStrEqual(URI,
9336 attr->ns->
9337 href))) {
9338#ifdef DEBUG_STEP
9339 n++;
9340#endif
9341 addNode(list,
9342 (xmlNodePtr) attr);
9343 }
9344 }
9345 }
9346 break;
9347 }
9348 case XML_NAMESPACE_DECL:
9349 if (cur->type == XML_NAMESPACE_DECL) {
9350 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009351
Daniel Veillardf06307e2001-07-03 10:35:50 +00009352 if ((ns->prefix != NULL) && (name != NULL)
9353 && (xmlStrEqual(ns->prefix, name))) {
9354#ifdef DEBUG_STEP
9355 n++;
9356#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009357 xmlXPathNodeSetAddNs(list,
9358 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009359 }
9360 }
9361 break;
9362 default:
9363 break;
9364 }
9365 break;
9366 break;
9367 }
9368 } while (cur != NULL);
9369
9370 /*
9371 * If there is some predicate filtering do it now
9372 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009373 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009374 xmlXPathObjectPtr obj2;
9375
9376 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9377 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9378 CHECK_TYPE0(XPATH_NODESET);
9379 obj2 = valuePop(ctxt);
9380 list = obj2->nodesetval;
9381 obj2->nodesetval = NULL;
9382 xmlXPathFreeObject(obj2);
9383 }
9384 if (ret == NULL) {
9385 ret = list;
9386 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009387 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009388 xmlXPathFreeNodeSet(list);
9389 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009390 }
9391 ctxt->context->node = tmp;
9392#ifdef DEBUG_STEP
9393 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009394 "\nExamined %d nodes, found %d nodes at that step\n",
9395 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009396#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009397 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009398 if ((obj->boolval) && (obj->user != NULL)) {
9399 ctxt->value->boolval = 1;
9400 ctxt->value->user = obj->user;
9401 obj->user = NULL;
9402 obj->boolval = 0;
9403 }
9404 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009405 return(t);
9406}
9407
9408/**
9409 * xmlXPathNodeCollectAndTestNth:
9410 * @ctxt: the XPath Parser context
9411 * @op: the XPath precompiled step operation
9412 * @indx: the index to collect
9413 * @first: pointer to the first element in document order
9414 * @last: pointer to the last element in document order
9415 *
9416 * This is the function implementing a step: based on the current list
9417 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009418 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009419 *
9420 * Pushes the new NodeSet resulting from the search.
9421 * Returns the number of node traversed
9422 */
9423static int
9424xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9425 xmlXPathStepOpPtr op, int indx,
9426 xmlNodePtr * first, xmlNodePtr * last)
9427{
William M. Brack78637da2003-07-31 14:47:38 +00009428 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9429 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9430 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009431 const xmlChar *prefix = op->value4;
9432 const xmlChar *name = op->value5;
9433 const xmlChar *URI = NULL;
9434 int n = 0, t = 0;
9435
9436 int i;
9437 xmlNodeSetPtr list;
9438 xmlXPathTraversalFunction next = NULL;
9439 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9440 xmlNodePtr cur = NULL;
9441 xmlXPathObjectPtr obj;
9442 xmlNodeSetPtr nodelist;
9443 xmlNodePtr tmp;
9444
9445 CHECK_TYPE0(XPATH_NODESET);
9446 obj = valuePop(ctxt);
9447 addNode = xmlXPathNodeSetAdd;
9448 if (prefix != NULL) {
9449 URI = xmlXPathNsLookup(ctxt->context, prefix);
9450 if (URI == NULL)
9451 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9452 }
9453#ifdef DEBUG_STEP_NTH
9454 xmlGenericError(xmlGenericErrorContext, "new step : ");
9455 if (first != NULL) {
9456 if (*first != NULL)
9457 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9458 (*first)->name);
9459 else
9460 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9461 }
9462 if (last != NULL) {
9463 if (*last != NULL)
9464 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9465 (*last)->name);
9466 else
9467 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9468 }
9469#endif
9470 switch (axis) {
9471 case AXIS_ANCESTOR:
9472#ifdef DEBUG_STEP_NTH
9473 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9474#endif
9475 first = NULL;
9476 next = xmlXPathNextAncestor;
9477 break;
9478 case AXIS_ANCESTOR_OR_SELF:
9479#ifdef DEBUG_STEP_NTH
9480 xmlGenericError(xmlGenericErrorContext,
9481 "axis 'ancestors-or-self' ");
9482#endif
9483 first = NULL;
9484 next = xmlXPathNextAncestorOrSelf;
9485 break;
9486 case AXIS_ATTRIBUTE:
9487#ifdef DEBUG_STEP_NTH
9488 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9489#endif
9490 first = NULL;
9491 last = NULL;
9492 next = xmlXPathNextAttribute;
9493 break;
9494 case AXIS_CHILD:
9495#ifdef DEBUG_STEP_NTH
9496 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9497#endif
9498 last = NULL;
9499 next = xmlXPathNextChild;
9500 break;
9501 case AXIS_DESCENDANT:
9502#ifdef DEBUG_STEP_NTH
9503 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9504#endif
9505 last = NULL;
9506 next = xmlXPathNextDescendant;
9507 break;
9508 case AXIS_DESCENDANT_OR_SELF:
9509#ifdef DEBUG_STEP_NTH
9510 xmlGenericError(xmlGenericErrorContext,
9511 "axis 'descendant-or-self' ");
9512#endif
9513 last = NULL;
9514 next = xmlXPathNextDescendantOrSelf;
9515 break;
9516 case AXIS_FOLLOWING:
9517#ifdef DEBUG_STEP_NTH
9518 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9519#endif
9520 last = NULL;
9521 next = xmlXPathNextFollowing;
9522 break;
9523 case AXIS_FOLLOWING_SIBLING:
9524#ifdef DEBUG_STEP_NTH
9525 xmlGenericError(xmlGenericErrorContext,
9526 "axis 'following-siblings' ");
9527#endif
9528 last = NULL;
9529 next = xmlXPathNextFollowingSibling;
9530 break;
9531 case AXIS_NAMESPACE:
9532#ifdef DEBUG_STEP_NTH
9533 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9534#endif
9535 last = NULL;
9536 first = NULL;
9537 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9538 break;
9539 case AXIS_PARENT:
9540#ifdef DEBUG_STEP_NTH
9541 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9542#endif
9543 first = NULL;
9544 next = xmlXPathNextParent;
9545 break;
9546 case AXIS_PRECEDING:
9547#ifdef DEBUG_STEP_NTH
9548 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9549#endif
9550 first = NULL;
9551 next = xmlXPathNextPrecedingInternal;
9552 break;
9553 case AXIS_PRECEDING_SIBLING:
9554#ifdef DEBUG_STEP_NTH
9555 xmlGenericError(xmlGenericErrorContext,
9556 "axis 'preceding-sibling' ");
9557#endif
9558 first = NULL;
9559 next = xmlXPathNextPrecedingSibling;
9560 break;
9561 case AXIS_SELF:
9562#ifdef DEBUG_STEP_NTH
9563 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9564#endif
9565 first = NULL;
9566 last = NULL;
9567 next = xmlXPathNextSelf;
9568 break;
9569 }
9570 if (next == NULL)
9571 return(0);
9572
9573 nodelist = obj->nodesetval;
9574 if (nodelist == NULL) {
9575 xmlXPathFreeObject(obj);
9576 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9577 return(0);
9578 }
9579 addNode = xmlXPathNodeSetAddUnique;
9580#ifdef DEBUG_STEP_NTH
9581 xmlGenericError(xmlGenericErrorContext,
9582 " context contains %d nodes\n", nodelist->nodeNr);
9583 switch (test) {
9584 case NODE_TEST_NONE:
9585 xmlGenericError(xmlGenericErrorContext,
9586 " searching for none !!!\n");
9587 break;
9588 case NODE_TEST_TYPE:
9589 xmlGenericError(xmlGenericErrorContext,
9590 " searching for type %d\n", type);
9591 break;
9592 case NODE_TEST_PI:
9593 xmlGenericError(xmlGenericErrorContext,
9594 " searching for PI !!!\n");
9595 break;
9596 case NODE_TEST_ALL:
9597 xmlGenericError(xmlGenericErrorContext,
9598 " searching for *\n");
9599 break;
9600 case NODE_TEST_NS:
9601 xmlGenericError(xmlGenericErrorContext,
9602 " searching for namespace %s\n",
9603 prefix);
9604 break;
9605 case NODE_TEST_NAME:
9606 xmlGenericError(xmlGenericErrorContext,
9607 " searching for name %s\n", name);
9608 if (prefix != NULL)
9609 xmlGenericError(xmlGenericErrorContext,
9610 " with namespace %s\n", prefix);
9611 break;
9612 }
9613 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9614#endif
9615 /*
9616 * 2.3 Node Tests
9617 * - For the attribute axis, the principal node type is attribute.
9618 * - For the namespace axis, the principal node type is namespace.
9619 * - For other axes, the principal node type is element.
9620 *
9621 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009622 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009623 * select all element children of the context node
9624 */
9625 tmp = ctxt->context->node;
9626 list = xmlXPathNodeSetCreate(NULL);
9627 for (i = 0; i < nodelist->nodeNr; i++) {
9628 ctxt->context->node = nodelist->nodeTab[i];
9629
9630 cur = NULL;
9631 n = 0;
9632 do {
9633 cur = next(ctxt, cur);
9634 if (cur == NULL)
9635 break;
9636 if ((first != NULL) && (*first == cur))
9637 break;
9638 if (((t % 256) == 0) &&
9639 (first != NULL) && (*first != NULL) &&
9640 (xmlXPathCmpNodes(*first, cur) >= 0))
9641 break;
9642 if ((last != NULL) && (*last == cur))
9643 break;
9644 if (((t % 256) == 0) &&
9645 (last != NULL) && (*last != NULL) &&
9646 (xmlXPathCmpNodes(cur, *last) >= 0))
9647 break;
9648 t++;
9649 switch (test) {
9650 case NODE_TEST_NONE:
9651 ctxt->context->node = tmp;
9652 STRANGE return(0);
9653 case NODE_TEST_TYPE:
9654 if ((cur->type == type) ||
9655 ((type == NODE_TYPE_NODE) &&
9656 ((cur->type == XML_DOCUMENT_NODE) ||
9657 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9658 (cur->type == XML_ELEMENT_NODE) ||
9659 (cur->type == XML_PI_NODE) ||
9660 (cur->type == XML_COMMENT_NODE) ||
9661 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009662 (cur->type == XML_TEXT_NODE))) ||
9663 ((type == NODE_TYPE_TEXT) &&
9664 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009665 n++;
9666 if (n == indx)
9667 addNode(list, cur);
9668 }
9669 break;
9670 case NODE_TEST_PI:
9671 if (cur->type == XML_PI_NODE) {
9672 if ((name != NULL) &&
9673 (!xmlStrEqual(name, cur->name)))
9674 break;
9675 n++;
9676 if (n == indx)
9677 addNode(list, cur);
9678 }
9679 break;
9680 case NODE_TEST_ALL:
9681 if (axis == AXIS_ATTRIBUTE) {
9682 if (cur->type == XML_ATTRIBUTE_NODE) {
9683 n++;
9684 if (n == indx)
9685 addNode(list, cur);
9686 }
9687 } else if (axis == AXIS_NAMESPACE) {
9688 if (cur->type == XML_NAMESPACE_DECL) {
9689 n++;
9690 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009691 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9692 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009693 }
9694 } else {
9695 if (cur->type == XML_ELEMENT_NODE) {
9696 if (prefix == NULL) {
9697 n++;
9698 if (n == indx)
9699 addNode(list, cur);
9700 } else if ((cur->ns != NULL) &&
9701 (xmlStrEqual(URI, cur->ns->href))) {
9702 n++;
9703 if (n == indx)
9704 addNode(list, cur);
9705 }
9706 }
9707 }
9708 break;
9709 case NODE_TEST_NS:{
9710 TODO;
9711 break;
9712 }
9713 case NODE_TEST_NAME:
9714 switch (cur->type) {
9715 case XML_ELEMENT_NODE:
9716 if (xmlStrEqual(name, cur->name)) {
9717 if (prefix == NULL) {
9718 if (cur->ns == NULL) {
9719 n++;
9720 if (n == indx)
9721 addNode(list, cur);
9722 }
9723 } else {
9724 if ((cur->ns != NULL) &&
9725 (xmlStrEqual(URI,
9726 cur->ns->href))) {
9727 n++;
9728 if (n == indx)
9729 addNode(list, cur);
9730 }
9731 }
9732 }
9733 break;
9734 case XML_ATTRIBUTE_NODE:{
9735 xmlAttrPtr attr = (xmlAttrPtr) cur;
9736
9737 if (xmlStrEqual(name, attr->name)) {
9738 if (prefix == NULL) {
9739 if ((attr->ns == NULL) ||
9740 (attr->ns->prefix == NULL)) {
9741 n++;
9742 if (n == indx)
9743 addNode(list, cur);
9744 }
9745 } else {
9746 if ((attr->ns != NULL) &&
9747 (xmlStrEqual(URI,
9748 attr->ns->
9749 href))) {
9750 n++;
9751 if (n == indx)
9752 addNode(list, cur);
9753 }
9754 }
9755 }
9756 break;
9757 }
9758 case XML_NAMESPACE_DECL:
9759 if (cur->type == XML_NAMESPACE_DECL) {
9760 xmlNsPtr ns = (xmlNsPtr) cur;
9761
9762 if ((ns->prefix != NULL) && (name != NULL)
9763 && (xmlStrEqual(ns->prefix, name))) {
9764 n++;
9765 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009766 xmlXPathNodeSetAddNs(list,
9767 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009768 }
9769 }
9770 break;
9771 default:
9772 break;
9773 }
9774 break;
9775 break;
9776 }
9777 } while (n < indx);
9778 }
9779 ctxt->context->node = tmp;
9780#ifdef DEBUG_STEP_NTH
9781 xmlGenericError(xmlGenericErrorContext,
9782 "\nExamined %d nodes, found %d nodes at that step\n",
9783 t, list->nodeNr);
9784#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009785 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009786 if ((obj->boolval) && (obj->user != NULL)) {
9787 ctxt->value->boolval = 1;
9788 ctxt->value->user = obj->user;
9789 obj->user = NULL;
9790 obj->boolval = 0;
9791 }
9792 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009793 return(t);
9794}
9795
9796/**
9797 * xmlXPathCompOpEvalFirst:
9798 * @ctxt: the XPath parser context with the compiled expression
9799 * @op: an XPath compiled operation
9800 * @first: the first elem found so far
9801 *
9802 * Evaluate the Precompiled XPath operation searching only the first
9803 * element in document order
9804 *
9805 * Returns the number of examined objects.
9806 */
9807static int
9808xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9809 xmlXPathStepOpPtr op, xmlNodePtr * first)
9810{
9811 int total = 0, cur;
9812 xmlXPathCompExprPtr comp;
9813 xmlXPathObjectPtr arg1, arg2;
9814
Daniel Veillard556c6682001-10-06 09:59:51 +00009815 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009816 comp = ctxt->comp;
9817 switch (op->op) {
9818 case XPATH_OP_END:
9819 return (0);
9820 case XPATH_OP_UNION:
9821 total =
9822 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9823 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009824 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009825 if ((ctxt->value != NULL)
9826 && (ctxt->value->type == XPATH_NODESET)
9827 && (ctxt->value->nodesetval != NULL)
9828 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9829 /*
9830 * limit tree traversing to first node in the result
9831 */
9832 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9833 *first = ctxt->value->nodesetval->nodeTab[0];
9834 }
9835 cur =
9836 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9837 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009838 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009839 CHECK_TYPE0(XPATH_NODESET);
9840 arg2 = valuePop(ctxt);
9841
9842 CHECK_TYPE0(XPATH_NODESET);
9843 arg1 = valuePop(ctxt);
9844
9845 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9846 arg2->nodesetval);
9847 valuePush(ctxt, arg1);
9848 xmlXPathFreeObject(arg2);
9849 /* optimizer */
9850 if (total > cur)
9851 xmlXPathCompSwap(op);
9852 return (total + cur);
9853 case XPATH_OP_ROOT:
9854 xmlXPathRoot(ctxt);
9855 return (0);
9856 case XPATH_OP_NODE:
9857 if (op->ch1 != -1)
9858 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009859 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009860 if (op->ch2 != -1)
9861 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009862 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009863 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9864 return (total);
9865 case XPATH_OP_RESET:
9866 if (op->ch1 != -1)
9867 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009868 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009869 if (op->ch2 != -1)
9870 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009871 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009872 ctxt->context->node = NULL;
9873 return (total);
9874 case XPATH_OP_COLLECT:{
9875 if (op->ch1 == -1)
9876 return (total);
9877
9878 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009879 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009880
9881 /*
9882 * Optimization for [n] selection where n is a number
9883 */
9884 if ((op->ch2 != -1) &&
9885 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9886 (comp->steps[op->ch2].ch1 == -1) &&
9887 (comp->steps[op->ch2].ch2 != -1) &&
9888 (comp->steps[comp->steps[op->ch2].ch2].op ==
9889 XPATH_OP_VALUE)) {
9890 xmlXPathObjectPtr val;
9891
9892 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9893 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9894 int indx = (int) val->floatval;
9895
9896 if (val->floatval == (float) indx) {
9897 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9898 first, NULL);
9899 return (total);
9900 }
9901 }
9902 }
9903 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9904 return (total);
9905 }
9906 case XPATH_OP_VALUE:
9907 valuePush(ctxt,
9908 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9909 return (0);
9910 case XPATH_OP_SORT:
9911 if (op->ch1 != -1)
9912 total +=
9913 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9914 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009915 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009916 if ((ctxt->value != NULL)
9917 && (ctxt->value->type == XPATH_NODESET)
9918 && (ctxt->value->nodesetval != NULL))
9919 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9920 return (total);
9921 default:
9922 return (xmlXPathCompOpEval(ctxt, op));
9923 }
9924}
9925
9926/**
9927 * xmlXPathCompOpEvalLast:
9928 * @ctxt: the XPath parser context with the compiled expression
9929 * @op: an XPath compiled operation
9930 * @last: the last elem found so far
9931 *
9932 * Evaluate the Precompiled XPath operation searching only the last
9933 * element in document order
9934 *
William M. Brack08171912003-12-29 02:52:11 +00009935 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +00009936 */
9937static int
9938xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9939 xmlNodePtr * last)
9940{
9941 int total = 0, cur;
9942 xmlXPathCompExprPtr comp;
9943 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +00009944 xmlNodePtr bak;
9945 xmlDocPtr bakd;
9946 int pp;
9947 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009948
Daniel Veillard556c6682001-10-06 09:59:51 +00009949 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009950 comp = ctxt->comp;
9951 switch (op->op) {
9952 case XPATH_OP_END:
9953 return (0);
9954 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +00009955 bakd = ctxt->context->doc;
9956 bak = ctxt->context->node;
9957 pp = ctxt->context->proximityPosition;
9958 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009959 total =
9960 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009961 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009962 if ((ctxt->value != NULL)
9963 && (ctxt->value->type == XPATH_NODESET)
9964 && (ctxt->value->nodesetval != NULL)
9965 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9966 /*
9967 * limit tree traversing to first node in the result
9968 */
9969 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9970 *last =
9971 ctxt->value->nodesetval->nodeTab[ctxt->value->
9972 nodesetval->nodeNr -
9973 1];
9974 }
William M. Brackce4fc562004-01-22 02:47:18 +00009975 ctxt->context->doc = bakd;
9976 ctxt->context->node = bak;
9977 ctxt->context->proximityPosition = pp;
9978 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009979 cur =
9980 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009981 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009982 if ((ctxt->value != NULL)
9983 && (ctxt->value->type == XPATH_NODESET)
9984 && (ctxt->value->nodesetval != NULL)
9985 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9986 }
9987 CHECK_TYPE0(XPATH_NODESET);
9988 arg2 = valuePop(ctxt);
9989
9990 CHECK_TYPE0(XPATH_NODESET);
9991 arg1 = valuePop(ctxt);
9992
9993 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9994 arg2->nodesetval);
9995 valuePush(ctxt, arg1);
9996 xmlXPathFreeObject(arg2);
9997 /* optimizer */
9998 if (total > cur)
9999 xmlXPathCompSwap(op);
10000 return (total + cur);
10001 case XPATH_OP_ROOT:
10002 xmlXPathRoot(ctxt);
10003 return (0);
10004 case XPATH_OP_NODE:
10005 if (op->ch1 != -1)
10006 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010007 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010008 if (op->ch2 != -1)
10009 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010010 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010011 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10012 return (total);
10013 case XPATH_OP_RESET:
10014 if (op->ch1 != -1)
10015 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010016 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010017 if (op->ch2 != -1)
10018 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010019 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010020 ctxt->context->node = NULL;
10021 return (total);
10022 case XPATH_OP_COLLECT:{
10023 if (op->ch1 == -1)
10024 return (0);
10025
10026 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010027 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010028
10029 /*
10030 * Optimization for [n] selection where n is a number
10031 */
10032 if ((op->ch2 != -1) &&
10033 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10034 (comp->steps[op->ch2].ch1 == -1) &&
10035 (comp->steps[op->ch2].ch2 != -1) &&
10036 (comp->steps[comp->steps[op->ch2].ch2].op ==
10037 XPATH_OP_VALUE)) {
10038 xmlXPathObjectPtr val;
10039
10040 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10041 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10042 int indx = (int) val->floatval;
10043
10044 if (val->floatval == (float) indx) {
10045 total +=
10046 xmlXPathNodeCollectAndTestNth(ctxt, op,
10047 indx, NULL,
10048 last);
10049 return (total);
10050 }
10051 }
10052 }
10053 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10054 return (total);
10055 }
10056 case XPATH_OP_VALUE:
10057 valuePush(ctxt,
10058 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10059 return (0);
10060 case XPATH_OP_SORT:
10061 if (op->ch1 != -1)
10062 total +=
10063 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10064 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010065 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010066 if ((ctxt->value != NULL)
10067 && (ctxt->value->type == XPATH_NODESET)
10068 && (ctxt->value->nodesetval != NULL))
10069 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10070 return (total);
10071 default:
10072 return (xmlXPathCompOpEval(ctxt, op));
10073 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010074}
10075
Owen Taylor3473f882001-02-23 17:55:21 +000010076/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010077 * xmlXPathCompOpEval:
10078 * @ctxt: the XPath parser context with the compiled expression
10079 * @op: an XPath compiled operation
10080 *
10081 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010082 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010083 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010084static int
10085xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10086{
10087 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010088 int equal, ret;
10089 xmlXPathCompExprPtr comp;
10090 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010091 xmlNodePtr bak;
10092 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010093 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010094 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010095
Daniel Veillard556c6682001-10-06 09:59:51 +000010096 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010097 comp = ctxt->comp;
10098 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010099 case XPATH_OP_END:
10100 return (0);
10101 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010102 bakd = ctxt->context->doc;
10103 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010104 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010105 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010106 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010107 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010108 xmlXPathBooleanFunction(ctxt, 1);
10109 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10110 return (total);
10111 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010112 ctxt->context->doc = bakd;
10113 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010114 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010115 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010116 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010117 if (ctxt->error) {
10118 xmlXPathFreeObject(arg2);
10119 return(0);
10120 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010121 xmlXPathBooleanFunction(ctxt, 1);
10122 arg1 = valuePop(ctxt);
10123 arg1->boolval &= arg2->boolval;
10124 valuePush(ctxt, arg1);
10125 xmlXPathFreeObject(arg2);
10126 return (total);
10127 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010128 bakd = ctxt->context->doc;
10129 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010130 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010131 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010132 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010133 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010134 xmlXPathBooleanFunction(ctxt, 1);
10135 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10136 return (total);
10137 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010138 ctxt->context->doc = bakd;
10139 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010140 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010141 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010142 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010143 if (ctxt->error) {
10144 xmlXPathFreeObject(arg2);
10145 return(0);
10146 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010147 xmlXPathBooleanFunction(ctxt, 1);
10148 arg1 = valuePop(ctxt);
10149 arg1->boolval |= arg2->boolval;
10150 valuePush(ctxt, arg1);
10151 xmlXPathFreeObject(arg2);
10152 return (total);
10153 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010154 bakd = ctxt->context->doc;
10155 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010156 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010157 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010158 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010159 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010160 ctxt->context->doc = bakd;
10161 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010162 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010163 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010164 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010165 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010166 if (op->value)
10167 equal = xmlXPathEqualValues(ctxt);
10168 else
10169 equal = xmlXPathNotEqualValues(ctxt);
10170 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010171 return (total);
10172 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010173 bakd = ctxt->context->doc;
10174 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010175 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010176 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010177 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010178 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010179 ctxt->context->doc = bakd;
10180 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010181 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010182 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010183 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010184 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010185 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10186 valuePush(ctxt, xmlXPathNewBoolean(ret));
10187 return (total);
10188 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010189 bakd = ctxt->context->doc;
10190 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010191 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010192 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010193 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010194 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010195 if (op->ch2 != -1) {
10196 ctxt->context->doc = bakd;
10197 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010198 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010199 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010200 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010201 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010202 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010203 if (op->value == 0)
10204 xmlXPathSubValues(ctxt);
10205 else if (op->value == 1)
10206 xmlXPathAddValues(ctxt);
10207 else if (op->value == 2)
10208 xmlXPathValueFlipSign(ctxt);
10209 else if (op->value == 3) {
10210 CAST_TO_NUMBER;
10211 CHECK_TYPE0(XPATH_NUMBER);
10212 }
10213 return (total);
10214 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010215 bakd = ctxt->context->doc;
10216 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010217 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010218 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010219 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010220 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010221 ctxt->context->doc = bakd;
10222 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010223 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010224 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010225 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010226 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010227 if (op->value == 0)
10228 xmlXPathMultValues(ctxt);
10229 else if (op->value == 1)
10230 xmlXPathDivValues(ctxt);
10231 else if (op->value == 2)
10232 xmlXPathModValues(ctxt);
10233 return (total);
10234 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010235 bakd = ctxt->context->doc;
10236 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010237 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010238 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010239 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010240 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010241 ctxt->context->doc = bakd;
10242 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010243 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010244 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010245 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010246 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010247 CHECK_TYPE0(XPATH_NODESET);
10248 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010249
Daniel Veillardf06307e2001-07-03 10:35:50 +000010250 CHECK_TYPE0(XPATH_NODESET);
10251 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010252
Daniel Veillardf06307e2001-07-03 10:35:50 +000010253 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10254 arg2->nodesetval);
10255 valuePush(ctxt, arg1);
10256 xmlXPathFreeObject(arg2);
10257 return (total);
10258 case XPATH_OP_ROOT:
10259 xmlXPathRoot(ctxt);
10260 return (total);
10261 case XPATH_OP_NODE:
10262 if (op->ch1 != -1)
10263 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010264 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010265 if (op->ch2 != -1)
10266 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010267 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010268 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10269 return (total);
10270 case XPATH_OP_RESET:
10271 if (op->ch1 != -1)
10272 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010273 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010274 if (op->ch2 != -1)
10275 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010276 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010277 ctxt->context->node = NULL;
10278 return (total);
10279 case XPATH_OP_COLLECT:{
10280 if (op->ch1 == -1)
10281 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010282
Daniel Veillardf06307e2001-07-03 10:35:50 +000010283 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010284 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010285
Daniel Veillardf06307e2001-07-03 10:35:50 +000010286 /*
10287 * Optimization for [n] selection where n is a number
10288 */
10289 if ((op->ch2 != -1) &&
10290 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10291 (comp->steps[op->ch2].ch1 == -1) &&
10292 (comp->steps[op->ch2].ch2 != -1) &&
10293 (comp->steps[comp->steps[op->ch2].ch2].op ==
10294 XPATH_OP_VALUE)) {
10295 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010296
Daniel Veillardf06307e2001-07-03 10:35:50 +000010297 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10298 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10299 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010300
Daniel Veillardf06307e2001-07-03 10:35:50 +000010301 if (val->floatval == (float) indx) {
10302 total +=
10303 xmlXPathNodeCollectAndTestNth(ctxt, op,
10304 indx, NULL,
10305 NULL);
10306 return (total);
10307 }
10308 }
10309 }
10310 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10311 return (total);
10312 }
10313 case XPATH_OP_VALUE:
10314 valuePush(ctxt,
10315 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10316 return (total);
10317 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010318 xmlXPathObjectPtr val;
10319
Daniel Veillardf06307e2001-07-03 10:35:50 +000010320 if (op->ch1 != -1)
10321 total +=
10322 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010323 if (op->value5 == NULL) {
10324 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10325 if (val == NULL) {
10326 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10327 return(0);
10328 }
10329 valuePush(ctxt, val);
10330 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010331 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010332
Daniel Veillardf06307e2001-07-03 10:35:50 +000010333 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10334 if (URI == NULL) {
10335 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010336 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010337 op->value4, op->value5);
10338 return (total);
10339 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010340 val = xmlXPathVariableLookupNS(ctxt->context,
10341 op->value4, URI);
10342 if (val == NULL) {
10343 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10344 return(0);
10345 }
10346 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010347 }
10348 return (total);
10349 }
10350 case XPATH_OP_FUNCTION:{
10351 xmlXPathFunction func;
10352 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010353 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010354
10355 if (op->ch1 != -1)
10356 total +=
10357 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010358 if (ctxt->valueNr < op->value) {
10359 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010360 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010361 ctxt->error = XPATH_INVALID_OPERAND;
10362 return (total);
10363 }
10364 for (i = 0; i < op->value; i++)
10365 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10366 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010367 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010368 ctxt->error = XPATH_INVALID_OPERAND;
10369 return (total);
10370 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010371 if (op->cache != NULL)
10372 func = (xmlXPathFunction) op->cache;
10373 else {
10374 const xmlChar *URI = NULL;
10375
10376 if (op->value5 == NULL)
10377 func =
10378 xmlXPathFunctionLookup(ctxt->context,
10379 op->value4);
10380 else {
10381 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10382 if (URI == NULL) {
10383 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010384 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010385 op->value4, op->value5);
10386 return (total);
10387 }
10388 func = xmlXPathFunctionLookupNS(ctxt->context,
10389 op->value4, URI);
10390 }
10391 if (func == NULL) {
10392 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010393 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010394 op->value4);
10395 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010396 }
10397 op->cache = (void *) func;
10398 op->cacheURI = (void *) URI;
10399 }
10400 oldFunc = ctxt->context->function;
10401 oldFuncURI = ctxt->context->functionURI;
10402 ctxt->context->function = op->value4;
10403 ctxt->context->functionURI = op->cacheURI;
10404 func(ctxt, op->value);
10405 ctxt->context->function = oldFunc;
10406 ctxt->context->functionURI = oldFuncURI;
10407 return (total);
10408 }
10409 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010410 bakd = ctxt->context->doc;
10411 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010412 if (op->ch1 != -1)
10413 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010414 ctxt->context->doc = bakd;
10415 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010416 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010417 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010418 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010419 ctxt->context->doc = bakd;
10420 ctxt->context->node = bak;
10421 CHECK_ERROR0;
10422 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010423 return (total);
10424 case XPATH_OP_PREDICATE:
10425 case XPATH_OP_FILTER:{
10426 xmlXPathObjectPtr res;
10427 xmlXPathObjectPtr obj, tmp;
10428 xmlNodeSetPtr newset = NULL;
10429 xmlNodeSetPtr oldset;
10430 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000010431 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010432 int i;
10433
10434 /*
10435 * Optimization for ()[1] selection i.e. the first elem
10436 */
10437 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10438 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10439 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10440 xmlXPathObjectPtr val;
10441
10442 val = comp->steps[op->ch2].value4;
10443 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10444 (val->floatval == 1.0)) {
10445 xmlNodePtr first = NULL;
10446
10447 total +=
10448 xmlXPathCompOpEvalFirst(ctxt,
10449 &comp->steps[op->ch1],
10450 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010451 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010452 /*
10453 * The nodeset should be in document order,
10454 * Keep only the first value
10455 */
10456 if ((ctxt->value != NULL) &&
10457 (ctxt->value->type == XPATH_NODESET) &&
10458 (ctxt->value->nodesetval != NULL) &&
10459 (ctxt->value->nodesetval->nodeNr > 1))
10460 ctxt->value->nodesetval->nodeNr = 1;
10461 return (total);
10462 }
10463 }
10464 /*
10465 * Optimization for ()[last()] selection i.e. the last elem
10466 */
10467 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10468 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10469 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10470 int f = comp->steps[op->ch2].ch1;
10471
10472 if ((f != -1) &&
10473 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10474 (comp->steps[f].value5 == NULL) &&
10475 (comp->steps[f].value == 0) &&
10476 (comp->steps[f].value4 != NULL) &&
10477 (xmlStrEqual
10478 (comp->steps[f].value4, BAD_CAST "last"))) {
10479 xmlNodePtr last = NULL;
10480
10481 total +=
10482 xmlXPathCompOpEvalLast(ctxt,
10483 &comp->steps[op->ch1],
10484 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010485 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010486 /*
10487 * The nodeset should be in document order,
10488 * Keep only the last value
10489 */
10490 if ((ctxt->value != NULL) &&
10491 (ctxt->value->type == XPATH_NODESET) &&
10492 (ctxt->value->nodesetval != NULL) &&
10493 (ctxt->value->nodesetval->nodeTab != NULL) &&
10494 (ctxt->value->nodesetval->nodeNr > 1)) {
10495 ctxt->value->nodesetval->nodeTab[0] =
10496 ctxt->value->nodesetval->nodeTab[ctxt->
10497 value->
10498 nodesetval->
10499 nodeNr -
10500 1];
10501 ctxt->value->nodesetval->nodeNr = 1;
10502 }
10503 return (total);
10504 }
10505 }
10506
10507 if (op->ch1 != -1)
10508 total +=
10509 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010510 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010511 if (op->ch2 == -1)
10512 return (total);
10513 if (ctxt->value == NULL)
10514 return (total);
10515
10516 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010517
10518#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010519 /*
10520 * Hum are we filtering the result of an XPointer expression
10521 */
10522 if (ctxt->value->type == XPATH_LOCATIONSET) {
10523 xmlLocationSetPtr newlocset = NULL;
10524 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010525
Daniel Veillardf06307e2001-07-03 10:35:50 +000010526 /*
10527 * Extract the old locset, and then evaluate the result of the
10528 * expression for all the element in the locset. use it to grow
10529 * up a new locset.
10530 */
10531 CHECK_TYPE0(XPATH_LOCATIONSET);
10532 obj = valuePop(ctxt);
10533 oldlocset = obj->user;
10534 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010535
Daniel Veillardf06307e2001-07-03 10:35:50 +000010536 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10537 ctxt->context->contextSize = 0;
10538 ctxt->context->proximityPosition = 0;
10539 if (op->ch2 != -1)
10540 total +=
10541 xmlXPathCompOpEval(ctxt,
10542 &comp->steps[op->ch2]);
10543 res = valuePop(ctxt);
10544 if (res != NULL)
10545 xmlXPathFreeObject(res);
10546 valuePush(ctxt, obj);
10547 CHECK_ERROR0;
10548 return (total);
10549 }
10550 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010551
Daniel Veillardf06307e2001-07-03 10:35:50 +000010552 for (i = 0; i < oldlocset->locNr; i++) {
10553 /*
10554 * Run the evaluation with a node list made of a
10555 * single item in the nodelocset.
10556 */
10557 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010558 ctxt->context->contextSize = oldlocset->locNr;
10559 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010560 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10561 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010562
Daniel Veillardf06307e2001-07-03 10:35:50 +000010563 if (op->ch2 != -1)
10564 total +=
10565 xmlXPathCompOpEval(ctxt,
10566 &comp->steps[op->ch2]);
10567 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010568
Daniel Veillardf06307e2001-07-03 10:35:50 +000010569 /*
10570 * The result of the evaluation need to be tested to
10571 * decided whether the filter succeeded or not
10572 */
10573 res = valuePop(ctxt);
10574 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10575 xmlXPtrLocationSetAdd(newlocset,
10576 xmlXPathObjectCopy
10577 (oldlocset->locTab[i]));
10578 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010579
Daniel Veillardf06307e2001-07-03 10:35:50 +000010580 /*
10581 * Cleanup
10582 */
10583 if (res != NULL)
10584 xmlXPathFreeObject(res);
10585 if (ctxt->value == tmp) {
10586 res = valuePop(ctxt);
10587 xmlXPathFreeObject(res);
10588 }
10589
10590 ctxt->context->node = NULL;
10591 }
10592
10593 /*
10594 * The result is used as the new evaluation locset.
10595 */
10596 xmlXPathFreeObject(obj);
10597 ctxt->context->node = NULL;
10598 ctxt->context->contextSize = -1;
10599 ctxt->context->proximityPosition = -1;
10600 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10601 ctxt->context->node = oldnode;
10602 return (total);
10603 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010604#endif /* LIBXML_XPTR_ENABLED */
10605
Daniel Veillardf06307e2001-07-03 10:35:50 +000010606 /*
10607 * Extract the old set, and then evaluate the result of the
10608 * expression for all the element in the set. use it to grow
10609 * up a new set.
10610 */
10611 CHECK_TYPE0(XPATH_NODESET);
10612 obj = valuePop(ctxt);
10613 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010614
Daniel Veillardf06307e2001-07-03 10:35:50 +000010615 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000010616 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010617 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010618
Daniel Veillardf06307e2001-07-03 10:35:50 +000010619 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10620 ctxt->context->contextSize = 0;
10621 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000010622/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000010623 if (op->ch2 != -1)
10624 total +=
10625 xmlXPathCompOpEval(ctxt,
10626 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010627 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010628 res = valuePop(ctxt);
10629 if (res != NULL)
10630 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000010631*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000010632 valuePush(ctxt, obj);
10633 ctxt->context->node = oldnode;
10634 CHECK_ERROR0;
10635 } else {
10636 /*
10637 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000010638 * Also set the xpath document in case things like
10639 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000010640 */
10641 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010642
Daniel Veillardf06307e2001-07-03 10:35:50 +000010643 for (i = 0; i < oldset->nodeNr; i++) {
10644 /*
10645 * Run the evaluation with a node list made of
10646 * a single item in the nodeset.
10647 */
10648 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000010649 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
10650 (oldset->nodeTab[i]->doc != NULL))
10651 ctxt->context->doc = oldset->nodeTab[i]->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010652 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10653 valuePush(ctxt, tmp);
10654 ctxt->context->contextSize = oldset->nodeNr;
10655 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010656
Daniel Veillardf06307e2001-07-03 10:35:50 +000010657 if (op->ch2 != -1)
10658 total +=
10659 xmlXPathCompOpEval(ctxt,
10660 &comp->steps[op->ch2]);
10661 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010662
Daniel Veillardf06307e2001-07-03 10:35:50 +000010663 /*
William M. Brack08171912003-12-29 02:52:11 +000010664 * The result of the evaluation needs to be tested to
10665 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010666 */
10667 res = valuePop(ctxt);
10668 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10669 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10670 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010671
Daniel Veillardf06307e2001-07-03 10:35:50 +000010672 /*
10673 * Cleanup
10674 */
10675 if (res != NULL)
10676 xmlXPathFreeObject(res);
10677 if (ctxt->value == tmp) {
10678 res = valuePop(ctxt);
10679 xmlXPathFreeObject(res);
10680 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010681
Daniel Veillardf06307e2001-07-03 10:35:50 +000010682 ctxt->context->node = NULL;
10683 }
10684
10685 /*
10686 * The result is used as the new evaluation set.
10687 */
10688 xmlXPathFreeObject(obj);
10689 ctxt->context->node = NULL;
10690 ctxt->context->contextSize = -1;
10691 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000010692 /* may want to move this past the '}' later */
10693 ctxt->context->doc = oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010694 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10695 }
10696 ctxt->context->node = oldnode;
10697 return (total);
10698 }
10699 case XPATH_OP_SORT:
10700 if (op->ch1 != -1)
10701 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010702 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010703 if ((ctxt->value != NULL) &&
10704 (ctxt->value->type == XPATH_NODESET) &&
10705 (ctxt->value->nodesetval != NULL))
10706 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10707 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010708#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010709 case XPATH_OP_RANGETO:{
10710 xmlXPathObjectPtr range;
10711 xmlXPathObjectPtr res, obj;
10712 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010713 xmlLocationSetPtr newlocset = NULL;
10714 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010715 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000010716 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010717
Daniel Veillardf06307e2001-07-03 10:35:50 +000010718 if (op->ch1 != -1)
10719 total +=
10720 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10721 if (op->ch2 == -1)
10722 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010723
William M. Brack08171912003-12-29 02:52:11 +000010724 if (ctxt->value->type == XPATH_LOCATIONSET) {
10725 /*
10726 * Extract the old locset, and then evaluate the result of the
10727 * expression for all the element in the locset. use it to grow
10728 * up a new locset.
10729 */
10730 CHECK_TYPE0(XPATH_LOCATIONSET);
10731 obj = valuePop(ctxt);
10732 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010733
William M. Brack08171912003-12-29 02:52:11 +000010734 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000010735 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000010736 ctxt->context->contextSize = 0;
10737 ctxt->context->proximityPosition = 0;
10738 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10739 res = valuePop(ctxt);
10740 if (res != NULL)
10741 xmlXPathFreeObject(res);
10742 valuePush(ctxt, obj);
10743 CHECK_ERROR0;
10744 return (total);
10745 }
10746 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010747
William M. Brack08171912003-12-29 02:52:11 +000010748 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010749 /*
William M. Brack08171912003-12-29 02:52:11 +000010750 * Run the evaluation with a node list made of a
10751 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010752 */
William M. Brackf7eb7942003-12-31 07:59:17 +000010753 ctxt->context->node = oldlocset->locTab[i]->user;
10754 ctxt->context->contextSize = oldlocset->locNr;
10755 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010756 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10757 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010758
Daniel Veillardf06307e2001-07-03 10:35:50 +000010759 if (op->ch2 != -1)
10760 total +=
10761 xmlXPathCompOpEval(ctxt,
10762 &comp->steps[op->ch2]);
10763 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010764
Daniel Veillardf06307e2001-07-03 10:35:50 +000010765 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000010766 if (res->type == XPATH_LOCATIONSET) {
10767 xmlLocationSetPtr rloc =
10768 (xmlLocationSetPtr)res->user;
10769 for (j=0; j<rloc->locNr; j++) {
10770 range = xmlXPtrNewRange(
10771 oldlocset->locTab[i]->user,
10772 oldlocset->locTab[i]->index,
10773 rloc->locTab[j]->user2,
10774 rloc->locTab[j]->index2);
10775 if (range != NULL) {
10776 xmlXPtrLocationSetAdd(newlocset, range);
10777 }
10778 }
10779 } else {
10780 range = xmlXPtrNewRangeNodeObject(
10781 (xmlNodePtr)oldlocset->locTab[i]->user, res);
10782 if (range != NULL) {
10783 xmlXPtrLocationSetAdd(newlocset,range);
10784 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010785 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010786
Daniel Veillardf06307e2001-07-03 10:35:50 +000010787 /*
10788 * Cleanup
10789 */
10790 if (res != NULL)
10791 xmlXPathFreeObject(res);
10792 if (ctxt->value == tmp) {
10793 res = valuePop(ctxt);
10794 xmlXPathFreeObject(res);
10795 }
10796
10797 ctxt->context->node = NULL;
10798 }
William M. Brack72ee48d2003-12-30 08:30:19 +000010799 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000010800 CHECK_TYPE0(XPATH_NODESET);
10801 obj = valuePop(ctxt);
10802 oldset = obj->nodesetval;
10803 ctxt->context->node = NULL;
10804
10805 newlocset = xmlXPtrLocationSetCreate(NULL);
10806
10807 if (oldset != NULL) {
10808 for (i = 0; i < oldset->nodeNr; i++) {
10809 /*
10810 * Run the evaluation with a node list made of a single item
10811 * in the nodeset.
10812 */
10813 ctxt->context->node = oldset->nodeTab[i];
10814 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10815 valuePush(ctxt, tmp);
10816
10817 if (op->ch2 != -1)
10818 total +=
10819 xmlXPathCompOpEval(ctxt,
10820 &comp->steps[op->ch2]);
10821 CHECK_ERROR0;
10822
William M. Brack08171912003-12-29 02:52:11 +000010823 res = valuePop(ctxt);
10824 range =
10825 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10826 res);
10827 if (range != NULL) {
10828 xmlXPtrLocationSetAdd(newlocset, range);
10829 }
10830
10831 /*
10832 * Cleanup
10833 */
10834 if (res != NULL)
10835 xmlXPathFreeObject(res);
10836 if (ctxt->value == tmp) {
10837 res = valuePop(ctxt);
10838 xmlXPathFreeObject(res);
10839 }
10840
10841 ctxt->context->node = NULL;
10842 }
10843 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010844 }
10845
10846 /*
10847 * The result is used as the new evaluation set.
10848 */
10849 xmlXPathFreeObject(obj);
10850 ctxt->context->node = NULL;
10851 ctxt->context->contextSize = -1;
10852 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010853 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010854 return (total);
10855 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010856#endif /* LIBXML_XPTR_ENABLED */
10857 }
10858 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010859 "XPath: unknown precompiled operation %d\n", op->op);
10860 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010861}
10862
10863/**
10864 * xmlXPathRunEval:
10865 * @ctxt: the XPath parser context with the compiled expression
10866 *
10867 * Evaluate the Precompiled XPath expression in the given context.
10868 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010869static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010870xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10871 xmlXPathCompExprPtr comp;
10872
10873 if ((ctxt == NULL) || (ctxt->comp == NULL))
10874 return;
10875
10876 if (ctxt->valueTab == NULL) {
10877 /* Allocate the value stack */
10878 ctxt->valueTab = (xmlXPathObjectPtr *)
10879 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10880 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010881 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010882 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010883 }
10884 ctxt->valueNr = 0;
10885 ctxt->valueMax = 10;
10886 ctxt->value = NULL;
10887 }
10888 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010889 if(comp->last < 0) {
10890 xmlGenericError(xmlGenericErrorContext,
10891 "xmlXPathRunEval: last is less than zero\n");
10892 return;
10893 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010894 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10895}
10896
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010897/************************************************************************
10898 * *
10899 * Public interfaces *
10900 * *
10901 ************************************************************************/
10902
10903/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010904 * xmlXPathEvalPredicate:
10905 * @ctxt: the XPath context
10906 * @res: the Predicate Expression evaluation result
10907 *
10908 * Evaluate a predicate result for the current node.
10909 * A PredicateExpr is evaluated by evaluating the Expr and converting
10910 * the result to a boolean. If the result is a number, the result will
10911 * be converted to true if the number is equal to the position of the
10912 * context node in the context node list (as returned by the position
10913 * function) and will be converted to false otherwise; if the result
10914 * is not a number, then the result will be converted as if by a call
10915 * to the boolean function.
10916 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010917 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010918 */
10919int
10920xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000010921 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010922 switch (res->type) {
10923 case XPATH_BOOLEAN:
10924 return(res->boolval);
10925 case XPATH_NUMBER:
10926 return(res->floatval == ctxt->proximityPosition);
10927 case XPATH_NODESET:
10928 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010929 if (res->nodesetval == NULL)
10930 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010931 return(res->nodesetval->nodeNr != 0);
10932 case XPATH_STRING:
10933 return((res->stringval != NULL) &&
10934 (xmlStrlen(res->stringval) != 0));
10935 default:
10936 STRANGE
10937 }
10938 return(0);
10939}
10940
10941/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010942 * xmlXPathEvaluatePredicateResult:
10943 * @ctxt: the XPath Parser context
10944 * @res: the Predicate Expression evaluation result
10945 *
10946 * Evaluate a predicate result for the current node.
10947 * A PredicateExpr is evaluated by evaluating the Expr and converting
10948 * the result to a boolean. If the result is a number, the result will
10949 * be converted to true if the number is equal to the position of the
10950 * context node in the context node list (as returned by the position
10951 * function) and will be converted to false otherwise; if the result
10952 * is not a number, then the result will be converted as if by a call
10953 * to the boolean function.
10954 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010955 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010956 */
10957int
10958xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10959 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000010960 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010961 switch (res->type) {
10962 case XPATH_BOOLEAN:
10963 return(res->boolval);
10964 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000010965#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000010966 return((res->floatval == ctxt->context->proximityPosition) &&
10967 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000010968#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010969 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000010970#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010971 case XPATH_NODESET:
10972 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010973 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010974 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010975 return(res->nodesetval->nodeNr != 0);
10976 case XPATH_STRING:
10977 return((res->stringval != NULL) &&
10978 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000010979#ifdef LIBXML_XPTR_ENABLED
10980 case XPATH_LOCATIONSET:{
10981 xmlLocationSetPtr ptr = res->user;
10982 if (ptr == NULL)
10983 return(0);
10984 return (ptr->locNr != 0);
10985 }
10986#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010987 default:
10988 STRANGE
10989 }
10990 return(0);
10991}
10992
10993/**
Daniel Veillard4773df22004-01-23 13:15:13 +000010994 * xmlXPathCtxtCompile:
10995 * @ctxt: an XPath context
10996 * @str: the XPath expression
10997 *
10998 * Compile an XPath expression
10999 *
11000 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
11001 * the caller has to free the object.
11002 */
11003xmlXPathCompExprPtr
11004xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11005 xmlXPathParserContextPtr pctxt;
11006 xmlXPathCompExprPtr comp;
11007
11008 xmlXPathInit();
11009
11010 pctxt = xmlXPathNewParserContext(str, ctxt);
11011 xmlXPathCompileExpr(pctxt);
11012
11013 if( pctxt->error != XPATH_EXPRESSION_OK )
11014 {
11015 xmlXPathFreeParserContext(pctxt);
11016 return (0);
11017 }
11018
11019 if (*pctxt->cur != 0) {
11020 /*
11021 * aleksey: in some cases this line prints *second* error message
11022 * (see bug #78858) and probably this should be fixed.
11023 * However, we are not sure that all error messages are printed
11024 * out in other places. It's not critical so we leave it as-is for now
11025 */
11026 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11027 comp = NULL;
11028 } else {
11029 comp = pctxt->comp;
11030 pctxt->comp = NULL;
11031 }
11032 xmlXPathFreeParserContext(pctxt);
11033 if (comp != NULL) {
11034 comp->expr = xmlStrdup(str);
11035#ifdef DEBUG_EVAL_COUNTS
11036 comp->string = xmlStrdup(str);
11037 comp->nb = 0;
11038#endif
11039 }
11040 return(comp);
11041}
11042
11043/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011044 * xmlXPathCompile:
11045 * @str: the XPath expression
11046 *
11047 * Compile an XPath expression
11048 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000011049 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011050 * the caller has to free the object.
11051 */
11052xmlXPathCompExprPtr
11053xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000011054 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011055}
11056
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011057/**
11058 * xmlXPathCompiledEval:
11059 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000011060 * @ctx: the XPath context
11061 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011062 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000011063 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011064 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000011065 * the caller has to free the object.
11066 */
11067xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011068xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000011069 xmlXPathParserContextPtr ctxt;
11070 xmlXPathObjectPtr res, tmp, init = NULL;
11071 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000011072#ifndef LIBXML_THREAD_ENABLED
11073 static int reentance = 0;
11074#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011075
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011076 if ((comp == NULL) || (ctx == NULL))
11077 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011078 xmlXPathInit();
11079
11080 CHECK_CONTEXT(ctx)
11081
Daniel Veillard81463942001-10-16 12:34:39 +000011082#ifndef LIBXML_THREAD_ENABLED
11083 reentance++;
11084 if (reentance > 1)
11085 xmlXPathDisableOptimizer = 1;
11086#endif
11087
Daniel Veillardf06307e2001-07-03 10:35:50 +000011088#ifdef DEBUG_EVAL_COUNTS
11089 comp->nb++;
11090 if ((comp->string != NULL) && (comp->nb > 100)) {
11091 fprintf(stderr, "100 x %s\n", comp->string);
11092 comp->nb = 0;
11093 }
11094#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011095 ctxt = xmlXPathCompParserContext(comp, ctx);
11096 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011097
11098 if (ctxt->value == NULL) {
11099 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011100 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011101 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011102 } else {
11103 res = valuePop(ctxt);
11104 }
11105
Daniel Veillardf06307e2001-07-03 10:35:50 +000011106
Owen Taylor3473f882001-02-23 17:55:21 +000011107 do {
11108 tmp = valuePop(ctxt);
11109 if (tmp != NULL) {
11110 if (tmp != init)
11111 stack++;
11112 xmlXPathFreeObject(tmp);
11113 }
11114 } while (tmp != NULL);
11115 if ((stack != 0) && (res != NULL)) {
11116 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011117 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011118 stack);
11119 }
11120 if (ctxt->error != XPATH_EXPRESSION_OK) {
11121 xmlXPathFreeObject(res);
11122 res = NULL;
11123 }
11124
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011125
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011126 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011127 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011128#ifndef LIBXML_THREAD_ENABLED
11129 reentance--;
11130#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011131 return(res);
11132}
11133
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011134/**
11135 * xmlXPathEvalExpr:
11136 * @ctxt: the XPath Parser context
11137 *
11138 * Parse and evaluate an XPath expression in the given context,
11139 * then push the result on the context stack
11140 */
11141void
11142xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
11143 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011144 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011145 xmlXPathRunEval(ctxt);
11146}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011147
11148/**
11149 * xmlXPathEval:
11150 * @str: the XPath expression
11151 * @ctx: the XPath context
11152 *
11153 * Evaluate the XPath Location Path in the given context.
11154 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011155 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011156 * the caller has to free the object.
11157 */
11158xmlXPathObjectPtr
11159xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11160 xmlXPathParserContextPtr ctxt;
11161 xmlXPathObjectPtr res, tmp, init = NULL;
11162 int stack = 0;
11163
11164 xmlXPathInit();
11165
11166 CHECK_CONTEXT(ctx)
11167
11168 ctxt = xmlXPathNewParserContext(str, ctx);
11169 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011170
11171 if (ctxt->value == NULL) {
11172 xmlGenericError(xmlGenericErrorContext,
11173 "xmlXPathEval: evaluation failed\n");
11174 res = NULL;
11175 } else if (*ctxt->cur != 0) {
11176 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11177 res = NULL;
11178 } else {
11179 res = valuePop(ctxt);
11180 }
11181
11182 do {
11183 tmp = valuePop(ctxt);
11184 if (tmp != NULL) {
11185 if (tmp != init)
11186 stack++;
11187 xmlXPathFreeObject(tmp);
11188 }
11189 } while (tmp != NULL);
11190 if ((stack != 0) && (res != NULL)) {
11191 xmlGenericError(xmlGenericErrorContext,
11192 "xmlXPathEval: %d object left on the stack\n",
11193 stack);
11194 }
11195 if (ctxt->error != XPATH_EXPRESSION_OK) {
11196 xmlXPathFreeObject(res);
11197 res = NULL;
11198 }
11199
Owen Taylor3473f882001-02-23 17:55:21 +000011200 xmlXPathFreeParserContext(ctxt);
11201 return(res);
11202}
11203
11204/**
11205 * xmlXPathEvalExpression:
11206 * @str: the XPath expression
11207 * @ctxt: the XPath context
11208 *
11209 * Evaluate the XPath expression in the given context.
11210 *
11211 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11212 * the caller has to free the object.
11213 */
11214xmlXPathObjectPtr
11215xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11216 xmlXPathParserContextPtr pctxt;
11217 xmlXPathObjectPtr res, tmp;
11218 int stack = 0;
11219
11220 xmlXPathInit();
11221
11222 CHECK_CONTEXT(ctxt)
11223
11224 pctxt = xmlXPathNewParserContext(str, ctxt);
11225 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011226
11227 if (*pctxt->cur != 0) {
11228 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11229 res = NULL;
11230 } else {
11231 res = valuePop(pctxt);
11232 }
11233 do {
11234 tmp = valuePop(pctxt);
11235 if (tmp != NULL) {
11236 xmlXPathFreeObject(tmp);
11237 stack++;
11238 }
11239 } while (tmp != NULL);
11240 if ((stack != 0) && (res != NULL)) {
11241 xmlGenericError(xmlGenericErrorContext,
11242 "xmlXPathEvalExpression: %d object left on the stack\n",
11243 stack);
11244 }
11245 xmlXPathFreeParserContext(pctxt);
11246 return(res);
11247}
11248
Daniel Veillard42766c02002-08-22 20:52:17 +000011249/************************************************************************
11250 * *
11251 * Extra functions not pertaining to the XPath spec *
11252 * *
11253 ************************************************************************/
11254/**
11255 * xmlXPathEscapeUriFunction:
11256 * @ctxt: the XPath Parser context
11257 * @nargs: the number of arguments
11258 *
11259 * Implement the escape-uri() XPath function
11260 * string escape-uri(string $str, bool $escape-reserved)
11261 *
11262 * This function applies the URI escaping rules defined in section 2 of [RFC
11263 * 2396] to the string supplied as $uri-part, which typically represents all
11264 * or part of a URI. The effect of the function is to replace any special
11265 * character in the string by an escape sequence of the form %xx%yy...,
11266 * where xxyy... is the hexadecimal representation of the octets used to
11267 * represent the character in UTF-8.
11268 *
11269 * The set of characters that are escaped depends on the setting of the
11270 * boolean argument $escape-reserved.
11271 *
11272 * If $escape-reserved is true, all characters are escaped other than lower
11273 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11274 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11275 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11276 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11277 * A-F).
11278 *
11279 * If $escape-reserved is false, the behavior differs in that characters
11280 * referred to in [RFC 2396] as reserved characters are not escaped. These
11281 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11282 *
11283 * [RFC 2396] does not define whether escaped URIs should use lower case or
11284 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11285 * compared using string comparison functions, this function must always use
11286 * the upper-case letters A-F.
11287 *
11288 * Generally, $escape-reserved should be set to true when escaping a string
11289 * that is to form a single part of a URI, and to false when escaping an
11290 * entire URI or URI reference.
11291 *
11292 * In the case of non-ascii characters, the string is encoded according to
11293 * utf-8 and then converted according to RFC 2396.
11294 *
11295 * Examples
11296 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11297 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11298 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11299 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11300 *
11301 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011302static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011303xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11304 xmlXPathObjectPtr str;
11305 int escape_reserved;
11306 xmlBufferPtr target;
11307 xmlChar *cptr;
11308 xmlChar escape[4];
11309
11310 CHECK_ARITY(2);
11311
11312 escape_reserved = xmlXPathPopBoolean(ctxt);
11313
11314 CAST_TO_STRING;
11315 str = valuePop(ctxt);
11316
11317 target = xmlBufferCreate();
11318
11319 escape[0] = '%';
11320 escape[3] = 0;
11321
11322 if (target) {
11323 for (cptr = str->stringval; *cptr; cptr++) {
11324 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11325 (*cptr >= 'a' && *cptr <= 'z') ||
11326 (*cptr >= '0' && *cptr <= '9') ||
11327 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11328 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11329 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11330 (*cptr == '%' &&
11331 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11332 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11333 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11334 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11335 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11336 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11337 (!escape_reserved &&
11338 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11339 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11340 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11341 *cptr == ','))) {
11342 xmlBufferAdd(target, cptr, 1);
11343 } else {
11344 if ((*cptr >> 4) < 10)
11345 escape[1] = '0' + (*cptr >> 4);
11346 else
11347 escape[1] = 'A' - 10 + (*cptr >> 4);
11348 if ((*cptr & 0xF) < 10)
11349 escape[2] = '0' + (*cptr & 0xF);
11350 else
11351 escape[2] = 'A' - 10 + (*cptr & 0xF);
11352
11353 xmlBufferAdd(target, &escape[0], 3);
11354 }
11355 }
11356 }
11357 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11358 xmlBufferFree(target);
11359 xmlXPathFreeObject(str);
11360}
11361
Owen Taylor3473f882001-02-23 17:55:21 +000011362/**
11363 * xmlXPathRegisterAllFunctions:
11364 * @ctxt: the XPath context
11365 *
11366 * Registers all default XPath functions in this context
11367 */
11368void
11369xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11370{
11371 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11372 xmlXPathBooleanFunction);
11373 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11374 xmlXPathCeilingFunction);
11375 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11376 xmlXPathCountFunction);
11377 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11378 xmlXPathConcatFunction);
11379 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11380 xmlXPathContainsFunction);
11381 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11382 xmlXPathIdFunction);
11383 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11384 xmlXPathFalseFunction);
11385 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11386 xmlXPathFloorFunction);
11387 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11388 xmlXPathLastFunction);
11389 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11390 xmlXPathLangFunction);
11391 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11392 xmlXPathLocalNameFunction);
11393 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11394 xmlXPathNotFunction);
11395 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11396 xmlXPathNameFunction);
11397 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11398 xmlXPathNamespaceURIFunction);
11399 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11400 xmlXPathNormalizeFunction);
11401 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11402 xmlXPathNumberFunction);
11403 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11404 xmlXPathPositionFunction);
11405 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11406 xmlXPathRoundFunction);
11407 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11408 xmlXPathStringFunction);
11409 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11410 xmlXPathStringLengthFunction);
11411 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11412 xmlXPathStartsWithFunction);
11413 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11414 xmlXPathSubstringFunction);
11415 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11416 xmlXPathSubstringBeforeFunction);
11417 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11418 xmlXPathSubstringAfterFunction);
11419 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11420 xmlXPathSumFunction);
11421 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11422 xmlXPathTrueFunction);
11423 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11424 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011425
11426 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11427 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11428 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011429}
11430
11431#endif /* LIBXML_XPATH_ENABLED */