blob: 9bbfdce9f5493d675c78668a0f43dc9a83a782b6 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
Owen Taylor3473f882001-02-23 17:55:21 +000031#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000034#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000035#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#endif
Owen Taylor3473f882001-02-23 17:55:21 +000037
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000052#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000053#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000054
Daniel Veillardd96f6d32003-10-07 21:25:12 +000055#define TODO \
56 xmlGenericError(xmlGenericErrorContext, \
57 "Unimplemented block at %s:%d\n", \
58 __FILE__, __LINE__);
59
Daniel Veillard4432df22003-09-28 18:58:27 +000060#if defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000061/************************************************************************
62 * *
63 * Floating point stuff *
64 * *
65 ************************************************************************/
66
Daniel Veillardc0631a62001-09-20 13:56:06 +000067#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000068#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000069#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000070#include "trionan.c"
71
Owen Taylor3473f882001-02-23 17:55:21 +000072/*
Owen Taylor3473f882001-02-23 17:55:21 +000073 * The lack of portability of this section of the libc is annoying !
74 */
75double xmlXPathNAN = 0;
76double xmlXPathPINF = 1;
77double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000078double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000079static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000080
Owen Taylor3473f882001-02-23 17:55:21 +000081/**
82 * xmlXPathInit:
83 *
84 * Initialize the XPath environment
85 */
86void
87xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +000088 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +000089
Bjorn Reese45029602001-08-21 09:23:53 +000090 xmlXPathPINF = trio_pinf();
91 xmlXPathNINF = trio_ninf();
92 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +000093 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +000094
Daniel Veillard20ee8c02001-10-05 09:18:14 +000095 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000096}
97
Daniel Veillardcda96922001-08-21 10:56:31 +000098/**
99 * xmlXPathIsNaN:
100 * @val: a double value
101 *
102 * Provides a portable isnan() function to detect whether a double
103 * is a NotaNumber. Based on trio code
104 * http://sourceforge.net/projects/ctrio/
105 *
106 * Returns 1 if the value is a NaN, 0 otherwise
107 */
108int
109xmlXPathIsNaN(double val) {
110 return(trio_isnan(val));
111}
112
113/**
114 * xmlXPathIsInf:
115 * @val: a double value
116 *
117 * Provides a portable isinf() function to detect whether a double
118 * is a +Infinite or -Infinite. Based on trio code
119 * http://sourceforge.net/projects/ctrio/
120 *
121 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
122 */
123int
124xmlXPathIsInf(double val) {
125 return(trio_isinf(val));
126}
127
Daniel Veillard4432df22003-09-28 18:58:27 +0000128#endif /* SCHEMAS or XPATH */
129#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000130/**
131 * xmlXPathGetSign:
132 * @val: a double value
133 *
134 * Provides a portable function to detect the sign of a double
135 * Modified from trio code
136 * http://sourceforge.net/projects/ctrio/
137 *
138 * Returns 1 if the value is Negative, 0 if positive
139 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000140static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000141xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000142 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000143}
144
145
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000146/*
147 * TODO: when compatibility allows remove all "fake node libxslt" strings
148 * the test should just be name[0] = ' '
149 */
150/* #define DEBUG */
151/* #define DEBUG_STEP */
152/* #define DEBUG_STEP_NTH */
153/* #define DEBUG_EXPR */
154/* #define DEBUG_EVAL_COUNTS */
155
156static xmlNs xmlXPathXMLNamespaceStruct = {
157 NULL,
158 XML_NAMESPACE_DECL,
159 XML_XML_NAMESPACE,
160 BAD_CAST "xml",
161 NULL
162};
163static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
164#ifndef LIBXML_THREAD_ENABLED
165/*
166 * Optimizer is disabled only when threaded apps are detected while
167 * the library ain't compiled for thread safety.
168 */
169static int xmlXPathDisableOptimizer = 0;
170#endif
171
Owen Taylor3473f882001-02-23 17:55:21 +0000172/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000173 * *
174 * Error handling routines *
175 * *
176 ************************************************************************/
177
William M. Brack08171912003-12-29 02:52:11 +0000178/*
179 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
180 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000181static const char *xmlXPathErrorMessages[] = {
182 "Ok\n",
183 "Number encoding\n",
184 "Unfinished literal\n",
185 "Start of literal\n",
186 "Expected $ for variable reference\n",
187 "Undefined variable\n",
188 "Invalid predicate\n",
189 "Invalid expression\n",
190 "Missing closing curly brace\n",
191 "Unregistered function\n",
192 "Invalid operand\n",
193 "Invalid type\n",
194 "Invalid number of arguments\n",
195 "Invalid context size\n",
196 "Invalid context position\n",
197 "Memory allocation error\n",
198 "Syntax error\n",
199 "Resource error\n",
200 "Sub resource error\n",
201 "Undefined namespace prefix\n",
202 "Encoding error\n",
203 "Char out of XML range\n"
204};
205
206
207/**
208 * xmlXPathErrMemory:
209 * @ctxt: an XPath context
210 * @extra: extra informations
211 *
212 * Handle a redefinition of attribute error
213 */
214static void
215xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
216{
217 if (ctxt != NULL) {
218 if (extra) {
219 xmlChar buf[200];
220
221 xmlStrPrintf(buf, 200,
222 BAD_CAST "Memory allocation failed : %s\n",
223 extra);
224 ctxt->lastError.message = (char *) xmlStrdup(buf);
225 } else {
226 ctxt->lastError.message = (char *)
227 xmlStrdup(BAD_CAST "Memory allocation failed\n");
228 }
229 ctxt->lastError.domain = XML_FROM_XPATH;
230 ctxt->lastError.code = XML_ERR_NO_MEMORY;
231 if (ctxt->error != NULL)
232 ctxt->error(ctxt->userData, &ctxt->lastError);
233 } else {
234 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000235 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000236 NULL, NULL, XML_FROM_XPATH,
237 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
238 extra, NULL, NULL, 0, 0,
239 "Memory allocation failed : %s\n", extra);
240 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000241 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000242 NULL, NULL, XML_FROM_XPATH,
243 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
244 NULL, NULL, NULL, 0, 0,
245 "Memory allocation failed\n");
246 }
247}
248
249/**
250 * xmlXPathErrMemory:
251 * @ctxt: an XPath parser context
252 * @extra: extra informations
253 *
254 * Handle a redefinition of attribute error
255 */
256static void
257xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
258{
259 ctxt->error = XPATH_MEMORY_ERROR;
260 if (ctxt == NULL)
261 xmlXPathErrMemory(NULL, extra);
262 else
263 xmlXPathErrMemory(ctxt->context, extra);
264}
265
266/**
267 * xmlXPathErr:
268 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000269 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000270 *
271 * Handle a Relax NG Parsing error
272 */
273void
274xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
275{
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000276 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000277 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000278 NULL, NULL, XML_FROM_XPATH,
279 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
280 XML_ERR_ERROR, NULL, 0,
281 NULL, NULL, NULL, 0, 0,
282 xmlXPathErrorMessages[error]);
283 return;
284 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000285 ctxt->error = error;
286 if (ctxt->context == NULL) {
287 __xmlRaiseError(NULL, NULL, NULL,
288 NULL, NULL, XML_FROM_XPATH,
289 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
290 XML_ERR_ERROR, NULL, 0,
291 (const char *) ctxt->base, NULL, NULL,
292 ctxt->cur - ctxt->base, 0,
293 xmlXPathErrorMessages[error]);
294 return;
295 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000296 ctxt->context->lastError.domain = XML_FROM_XPATH;
297 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
298 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000299 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000300 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
301 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
302 ctxt->context->lastError.node = ctxt->context->debugNode;
303 if (ctxt->context->error != NULL) {
304 ctxt->context->error(ctxt->context->userData,
305 &ctxt->context->lastError);
306 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000307 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000308 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
309 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
310 XML_ERR_ERROR, NULL, 0,
311 (const char *) ctxt->base, NULL, NULL,
312 ctxt->cur - ctxt->base, 0,
313 xmlXPathErrorMessages[error]);
314 }
315
316}
317
318/**
319 * xmlXPatherror:
320 * @ctxt: the XPath Parser context
321 * @file: the file name
322 * @line: the line number
323 * @no: the error number
324 *
325 * Formats an error message.
326 */
327void
328xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
329 int line ATTRIBUTE_UNUSED, int no) {
330 xmlXPathErr(ctxt, no);
331}
332
333
334/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000335 * *
336 * Parser Types *
337 * *
338 ************************************************************************/
339
340/*
341 * Types are private:
342 */
343
344typedef enum {
345 XPATH_OP_END=0,
346 XPATH_OP_AND,
347 XPATH_OP_OR,
348 XPATH_OP_EQUAL,
349 XPATH_OP_CMP,
350 XPATH_OP_PLUS,
351 XPATH_OP_MULT,
352 XPATH_OP_UNION,
353 XPATH_OP_ROOT,
354 XPATH_OP_NODE,
355 XPATH_OP_RESET,
356 XPATH_OP_COLLECT,
357 XPATH_OP_VALUE,
358 XPATH_OP_VARIABLE,
359 XPATH_OP_FUNCTION,
360 XPATH_OP_ARG,
361 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000362 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000363 XPATH_OP_SORT
364#ifdef LIBXML_XPTR_ENABLED
365 ,XPATH_OP_RANGETO
366#endif
367} xmlXPathOp;
368
369typedef enum {
370 AXIS_ANCESTOR = 1,
371 AXIS_ANCESTOR_OR_SELF,
372 AXIS_ATTRIBUTE,
373 AXIS_CHILD,
374 AXIS_DESCENDANT,
375 AXIS_DESCENDANT_OR_SELF,
376 AXIS_FOLLOWING,
377 AXIS_FOLLOWING_SIBLING,
378 AXIS_NAMESPACE,
379 AXIS_PARENT,
380 AXIS_PRECEDING,
381 AXIS_PRECEDING_SIBLING,
382 AXIS_SELF
383} xmlXPathAxisVal;
384
385typedef enum {
386 NODE_TEST_NONE = 0,
387 NODE_TEST_TYPE = 1,
388 NODE_TEST_PI = 2,
389 NODE_TEST_ALL = 3,
390 NODE_TEST_NS = 4,
391 NODE_TEST_NAME = 5
392} xmlXPathTestVal;
393
394typedef enum {
395 NODE_TYPE_NODE = 0,
396 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
397 NODE_TYPE_TEXT = XML_TEXT_NODE,
398 NODE_TYPE_PI = XML_PI_NODE
399} xmlXPathTypeVal;
400
401
402typedef struct _xmlXPathStepOp xmlXPathStepOp;
403typedef xmlXPathStepOp *xmlXPathStepOpPtr;
404struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000405 xmlXPathOp op; /* The identifier of the operation */
406 int ch1; /* First child */
407 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000408 int value;
409 int value2;
410 int value3;
411 void *value4;
412 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000413 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000414 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000415};
416
417struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000418 int nbStep; /* Number of steps in this expression */
419 int maxStep; /* Maximum number of steps allocated */
420 xmlXPathStepOp *steps; /* ops for computation of this expression */
421 int last; /* index of last step in expression */
422 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000423 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000424#ifdef DEBUG_EVAL_COUNTS
425 int nb;
426 xmlChar *string;
427#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000428};
429
430/************************************************************************
431 * *
432 * Parser Type functions *
433 * *
434 ************************************************************************/
435
436/**
437 * xmlXPathNewCompExpr:
438 *
439 * Create a new Xpath component
440 *
441 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
442 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000443static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000444xmlXPathNewCompExpr(void) {
445 xmlXPathCompExprPtr cur;
446
447 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
448 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000449 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000450 return(NULL);
451 }
452 memset(cur, 0, sizeof(xmlXPathCompExpr));
453 cur->maxStep = 10;
454 cur->nbStep = 0;
455 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
456 sizeof(xmlXPathStepOp));
457 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000458 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000459 xmlFree(cur);
460 return(NULL);
461 }
462 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
463 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000464#ifdef DEBUG_EVAL_COUNTS
465 cur->nb = 0;
466#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000467 return(cur);
468}
469
470/**
471 * xmlXPathFreeCompExpr:
472 * @comp: an XPATH comp
473 *
474 * Free up the memory allocated by @comp
475 */
476void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000477xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
478{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000479 xmlXPathStepOpPtr op;
480 int i;
481
482 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000483 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000484 if (comp->dict == NULL) {
485 for (i = 0; i < comp->nbStep; i++) {
486 op = &comp->steps[i];
487 if (op->value4 != NULL) {
488 if (op->op == XPATH_OP_VALUE)
489 xmlXPathFreeObject(op->value4);
490 else
491 xmlFree(op->value4);
492 }
493 if (op->value5 != NULL)
494 xmlFree(op->value5);
495 }
496 } else {
497 for (i = 0; i < comp->nbStep; i++) {
498 op = &comp->steps[i];
499 if (op->value4 != NULL) {
500 if (op->op == XPATH_OP_VALUE)
501 xmlXPathFreeObject(op->value4);
502 }
503 }
504 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000505 }
506 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000507 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000508 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000509#ifdef DEBUG_EVAL_COUNTS
510 if (comp->string != NULL) {
511 xmlFree(comp->string);
512 }
513#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000514 if (comp->expr != NULL) {
515 xmlFree(comp->expr);
516 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000517
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000518 xmlFree(comp);
519}
520
521/**
522 * xmlXPathCompExprAdd:
523 * @comp: the compiled expression
524 * @ch1: first child index
525 * @ch2: second child index
526 * @op: an op
527 * @value: the first int value
528 * @value2: the second int value
529 * @value3: the third int value
530 * @value4: the first string value
531 * @value5: the second string value
532 *
William M. Brack08171912003-12-29 02:52:11 +0000533 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000534 *
535 * Returns -1 in case of failure, the index otherwise
536 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000537static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000538xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
539 xmlXPathOp op, int value,
540 int value2, int value3, void *value4, void *value5) {
541 if (comp->nbStep >= comp->maxStep) {
542 xmlXPathStepOp *real;
543
544 comp->maxStep *= 2;
545 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
546 comp->maxStep * sizeof(xmlXPathStepOp));
547 if (real == NULL) {
548 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000549 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000550 return(-1);
551 }
552 comp->steps = real;
553 }
554 comp->last = comp->nbStep;
555 comp->steps[comp->nbStep].ch1 = ch1;
556 comp->steps[comp->nbStep].ch2 = ch2;
557 comp->steps[comp->nbStep].op = op;
558 comp->steps[comp->nbStep].value = value;
559 comp->steps[comp->nbStep].value2 = value2;
560 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000561 if ((comp->dict != NULL) &&
562 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
563 (op == XPATH_OP_COLLECT))) {
564 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000565 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000566 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000567 xmlFree(value4);
568 } else
569 comp->steps[comp->nbStep].value4 = NULL;
570 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000571 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000572 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000573 xmlFree(value5);
574 } else
575 comp->steps[comp->nbStep].value5 = NULL;
576 } else {
577 comp->steps[comp->nbStep].value4 = value4;
578 comp->steps[comp->nbStep].value5 = value5;
579 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000580 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000581 return(comp->nbStep++);
582}
583
Daniel Veillardf06307e2001-07-03 10:35:50 +0000584/**
585 * xmlXPathCompSwap:
586 * @comp: the compiled expression
587 * @op: operation index
588 *
589 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000590 */
591static void
592xmlXPathCompSwap(xmlXPathStepOpPtr op) {
593 int tmp;
594
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000595#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000596 /*
597 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000598 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000599 * application
600 */
601 if (xmlXPathDisableOptimizer)
602 return;
603#endif
604
Daniel Veillardf06307e2001-07-03 10:35:50 +0000605 tmp = op->ch1;
606 op->ch1 = op->ch2;
607 op->ch2 = tmp;
608}
609
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000610#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
611 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
612 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000613#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
614 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
615 (op), (val), (val2), (val3), (val4), (val5))
616
617#define PUSH_LEAVE_EXPR(op, val, val2) \
618xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
619
620#define PUSH_UNARY_EXPR(op, ch, val, val2) \
621xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
622
623#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000624xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
625 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000626
627/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000628 * *
629 * Debugging related functions *
630 * *
631 ************************************************************************/
632
Owen Taylor3473f882001-02-23 17:55:21 +0000633#define STRANGE \
634 xmlGenericError(xmlGenericErrorContext, \
635 "Internal error at %s:%d\n", \
636 __FILE__, __LINE__);
637
638#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000639static void
640xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000641 int i;
642 char shift[100];
643
644 for (i = 0;((i < depth) && (i < 25));i++)
645 shift[2 * i] = shift[2 * i + 1] = ' ';
646 shift[2 * i] = shift[2 * i + 1] = 0;
647 if (cur == NULL) {
648 fprintf(output, shift);
649 fprintf(output, "Node is NULL !\n");
650 return;
651
652 }
653
654 if ((cur->type == XML_DOCUMENT_NODE) ||
655 (cur->type == XML_HTML_DOCUMENT_NODE)) {
656 fprintf(output, shift);
657 fprintf(output, " /\n");
658 } else if (cur->type == XML_ATTRIBUTE_NODE)
659 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
660 else
661 xmlDebugDumpOneNode(output, cur, depth);
662}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000663static void
664xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000665 xmlNodePtr tmp;
666 int i;
667 char shift[100];
668
669 for (i = 0;((i < depth) && (i < 25));i++)
670 shift[2 * i] = shift[2 * i + 1] = ' ';
671 shift[2 * i] = shift[2 * i + 1] = 0;
672 if (cur == NULL) {
673 fprintf(output, shift);
674 fprintf(output, "Node is NULL !\n");
675 return;
676
677 }
678
679 while (cur != NULL) {
680 tmp = cur;
681 cur = cur->next;
682 xmlDebugDumpOneNode(output, tmp, depth);
683 }
684}
Owen Taylor3473f882001-02-23 17:55:21 +0000685
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000686static void
687xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000688 int i;
689 char shift[100];
690
691 for (i = 0;((i < depth) && (i < 25));i++)
692 shift[2 * i] = shift[2 * i + 1] = ' ';
693 shift[2 * i] = shift[2 * i + 1] = 0;
694
695 if (cur == NULL) {
696 fprintf(output, shift);
697 fprintf(output, "NodeSet is NULL !\n");
698 return;
699
700 }
701
Daniel Veillard911f49a2001-04-07 15:39:35 +0000702 if (cur != NULL) {
703 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
704 for (i = 0;i < cur->nodeNr;i++) {
705 fprintf(output, shift);
706 fprintf(output, "%d", i + 1);
707 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
708 }
Owen Taylor3473f882001-02-23 17:55:21 +0000709 }
710}
711
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000712static void
713xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000714 int i;
715 char shift[100];
716
717 for (i = 0;((i < depth) && (i < 25));i++)
718 shift[2 * i] = shift[2 * i + 1] = ' ';
719 shift[2 * i] = shift[2 * i + 1] = 0;
720
721 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
722 fprintf(output, shift);
723 fprintf(output, "Value Tree is NULL !\n");
724 return;
725
726 }
727
728 fprintf(output, shift);
729 fprintf(output, "%d", i + 1);
730 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
731}
Owen Taylor3473f882001-02-23 17:55:21 +0000732#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000733static void
734xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000735 int i;
736 char shift[100];
737
738 for (i = 0;((i < depth) && (i < 25));i++)
739 shift[2 * i] = shift[2 * i + 1] = ' ';
740 shift[2 * i] = shift[2 * i + 1] = 0;
741
742 if (cur == NULL) {
743 fprintf(output, shift);
744 fprintf(output, "LocationSet is NULL !\n");
745 return;
746
747 }
748
749 for (i = 0;i < cur->locNr;i++) {
750 fprintf(output, shift);
751 fprintf(output, "%d : ", i + 1);
752 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
753 }
754}
Daniel Veillard017b1082001-06-21 11:20:21 +0000755#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000756
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000757/**
758 * xmlXPathDebugDumpObject:
759 * @output: the FILE * to dump the output
760 * @cur: the object to inspect
761 * @depth: indentation level
762 *
763 * Dump the content of the object for debugging purposes
764 */
765void
766xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000767 int i;
768 char shift[100];
769
770 for (i = 0;((i < depth) && (i < 25));i++)
771 shift[2 * i] = shift[2 * i + 1] = ' ';
772 shift[2 * i] = shift[2 * i + 1] = 0;
773
774 fprintf(output, shift);
775
776 if (cur == NULL) {
777 fprintf(output, "Object is empty (NULL)\n");
778 return;
779 }
780 switch(cur->type) {
781 case XPATH_UNDEFINED:
782 fprintf(output, "Object is uninitialized\n");
783 break;
784 case XPATH_NODESET:
785 fprintf(output, "Object is a Node Set :\n");
786 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
787 break;
788 case XPATH_XSLT_TREE:
789 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000790 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000791 break;
792 case XPATH_BOOLEAN:
793 fprintf(output, "Object is a Boolean : ");
794 if (cur->boolval) fprintf(output, "true\n");
795 else fprintf(output, "false\n");
796 break;
797 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000798 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000799 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000800 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000801 break;
802 case -1:
803 fprintf(output, "Object is a number : -Infinity\n");
804 break;
805 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000806 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000807 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000808 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
809 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000810 } else {
811 fprintf(output, "Object is a number : %0g\n", cur->floatval);
812 }
813 }
Owen Taylor3473f882001-02-23 17:55:21 +0000814 break;
815 case XPATH_STRING:
816 fprintf(output, "Object is a string : ");
817 xmlDebugDumpString(output, cur->stringval);
818 fprintf(output, "\n");
819 break;
820 case XPATH_POINT:
821 fprintf(output, "Object is a point : index %d in node", cur->index);
822 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
823 fprintf(output, "\n");
824 break;
825 case XPATH_RANGE:
826 if ((cur->user2 == NULL) ||
827 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
828 fprintf(output, "Object is a collapsed range :\n");
829 fprintf(output, shift);
830 if (cur->index >= 0)
831 fprintf(output, "index %d in ", cur->index);
832 fprintf(output, "node\n");
833 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
834 depth + 1);
835 } else {
836 fprintf(output, "Object is a range :\n");
837 fprintf(output, shift);
838 fprintf(output, "From ");
839 if (cur->index >= 0)
840 fprintf(output, "index %d in ", cur->index);
841 fprintf(output, "node\n");
842 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
843 depth + 1);
844 fprintf(output, shift);
845 fprintf(output, "To ");
846 if (cur->index2 >= 0)
847 fprintf(output, "index %d in ", cur->index2);
848 fprintf(output, "node\n");
849 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
850 depth + 1);
851 fprintf(output, "\n");
852 }
853 break;
854 case XPATH_LOCATIONSET:
855#if defined(LIBXML_XPTR_ENABLED)
856 fprintf(output, "Object is a Location Set:\n");
857 xmlXPathDebugDumpLocationSet(output,
858 (xmlLocationSetPtr) cur->user, depth);
859#endif
860 break;
861 case XPATH_USERS:
862 fprintf(output, "Object is user defined\n");
863 break;
864 }
865}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000866
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000867static void
868xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000869 xmlXPathStepOpPtr op, int depth) {
870 int i;
871 char shift[100];
872
873 for (i = 0;((i < depth) && (i < 25));i++)
874 shift[2 * i] = shift[2 * i + 1] = ' ';
875 shift[2 * i] = shift[2 * i + 1] = 0;
876
877 fprintf(output, shift);
878 if (op == NULL) {
879 fprintf(output, "Step is NULL\n");
880 return;
881 }
882 switch (op->op) {
883 case XPATH_OP_END:
884 fprintf(output, "END"); break;
885 case XPATH_OP_AND:
886 fprintf(output, "AND"); break;
887 case XPATH_OP_OR:
888 fprintf(output, "OR"); break;
889 case XPATH_OP_EQUAL:
890 if (op->value)
891 fprintf(output, "EQUAL =");
892 else
893 fprintf(output, "EQUAL !=");
894 break;
895 case XPATH_OP_CMP:
896 if (op->value)
897 fprintf(output, "CMP <");
898 else
899 fprintf(output, "CMP >");
900 if (!op->value2)
901 fprintf(output, "=");
902 break;
903 case XPATH_OP_PLUS:
904 if (op->value == 0)
905 fprintf(output, "PLUS -");
906 else if (op->value == 1)
907 fprintf(output, "PLUS +");
908 else if (op->value == 2)
909 fprintf(output, "PLUS unary -");
910 else if (op->value == 3)
911 fprintf(output, "PLUS unary - -");
912 break;
913 case XPATH_OP_MULT:
914 if (op->value == 0)
915 fprintf(output, "MULT *");
916 else if (op->value == 1)
917 fprintf(output, "MULT div");
918 else
919 fprintf(output, "MULT mod");
920 break;
921 case XPATH_OP_UNION:
922 fprintf(output, "UNION"); break;
923 case XPATH_OP_ROOT:
924 fprintf(output, "ROOT"); break;
925 case XPATH_OP_NODE:
926 fprintf(output, "NODE"); break;
927 case XPATH_OP_RESET:
928 fprintf(output, "RESET"); break;
929 case XPATH_OP_SORT:
930 fprintf(output, "SORT"); break;
931 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000932 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
933 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
934 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000935 const xmlChar *prefix = op->value4;
936 const xmlChar *name = op->value5;
937
938 fprintf(output, "COLLECT ");
939 switch (axis) {
940 case AXIS_ANCESTOR:
941 fprintf(output, " 'ancestors' "); break;
942 case AXIS_ANCESTOR_OR_SELF:
943 fprintf(output, " 'ancestors-or-self' "); break;
944 case AXIS_ATTRIBUTE:
945 fprintf(output, " 'attributes' "); break;
946 case AXIS_CHILD:
947 fprintf(output, " 'child' "); break;
948 case AXIS_DESCENDANT:
949 fprintf(output, " 'descendant' "); break;
950 case AXIS_DESCENDANT_OR_SELF:
951 fprintf(output, " 'descendant-or-self' "); break;
952 case AXIS_FOLLOWING:
953 fprintf(output, " 'following' "); break;
954 case AXIS_FOLLOWING_SIBLING:
955 fprintf(output, " 'following-siblings' "); break;
956 case AXIS_NAMESPACE:
957 fprintf(output, " 'namespace' "); break;
958 case AXIS_PARENT:
959 fprintf(output, " 'parent' "); break;
960 case AXIS_PRECEDING:
961 fprintf(output, " 'preceding' "); break;
962 case AXIS_PRECEDING_SIBLING:
963 fprintf(output, " 'preceding-sibling' "); break;
964 case AXIS_SELF:
965 fprintf(output, " 'self' "); break;
966 }
967 switch (test) {
968 case NODE_TEST_NONE:
969 fprintf(output, "'none' "); break;
970 case NODE_TEST_TYPE:
971 fprintf(output, "'type' "); break;
972 case NODE_TEST_PI:
973 fprintf(output, "'PI' "); break;
974 case NODE_TEST_ALL:
975 fprintf(output, "'all' "); break;
976 case NODE_TEST_NS:
977 fprintf(output, "'namespace' "); break;
978 case NODE_TEST_NAME:
979 fprintf(output, "'name' "); break;
980 }
981 switch (type) {
982 case NODE_TYPE_NODE:
983 fprintf(output, "'node' "); break;
984 case NODE_TYPE_COMMENT:
985 fprintf(output, "'comment' "); break;
986 case NODE_TYPE_TEXT:
987 fprintf(output, "'text' "); break;
988 case NODE_TYPE_PI:
989 fprintf(output, "'PI' "); break;
990 }
991 if (prefix != NULL)
992 fprintf(output, "%s:", prefix);
993 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +0000994 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000995 break;
996
997 }
998 case XPATH_OP_VALUE: {
999 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1000
1001 fprintf(output, "ELEM ");
1002 xmlXPathDebugDumpObject(output, object, 0);
1003 goto finish;
1004 }
1005 case XPATH_OP_VARIABLE: {
1006 const xmlChar *prefix = op->value5;
1007 const xmlChar *name = op->value4;
1008
1009 if (prefix != NULL)
1010 fprintf(output, "VARIABLE %s:%s", prefix, name);
1011 else
1012 fprintf(output, "VARIABLE %s", name);
1013 break;
1014 }
1015 case XPATH_OP_FUNCTION: {
1016 int nbargs = op->value;
1017 const xmlChar *prefix = op->value5;
1018 const xmlChar *name = op->value4;
1019
1020 if (prefix != NULL)
1021 fprintf(output, "FUNCTION %s:%s(%d args)",
1022 prefix, name, nbargs);
1023 else
1024 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1025 break;
1026 }
1027 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1028 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001029 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001030#ifdef LIBXML_XPTR_ENABLED
1031 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1032#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001033 default:
1034 fprintf(output, "UNKNOWN %d\n", op->op); return;
1035 }
1036 fprintf(output, "\n");
1037finish:
1038 if (op->ch1 >= 0)
1039 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1040 if (op->ch2 >= 0)
1041 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1042}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001043
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001044/**
1045 * xmlXPathDebugDumpCompExpr:
1046 * @output: the FILE * for the output
1047 * @comp: the precompiled XPath expression
1048 * @depth: the indentation level.
1049 *
1050 * Dumps the tree of the compiled XPath expression.
1051 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001052void
1053xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1054 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001055 int i;
1056 char shift[100];
1057
1058 for (i = 0;((i < depth) && (i < 25));i++)
1059 shift[2 * i] = shift[2 * i + 1] = ' ';
1060 shift[2 * i] = shift[2 * i + 1] = 0;
1061
1062 fprintf(output, shift);
1063
1064 if (comp == NULL) {
1065 fprintf(output, "Compiled Expression is NULL\n");
1066 return;
1067 }
1068 fprintf(output, "Compiled Expression : %d elements\n",
1069 comp->nbStep);
1070 i = comp->last;
1071 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1072}
Daniel Veillard017b1082001-06-21 11:20:21 +00001073#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001074
1075/************************************************************************
1076 * *
1077 * Parser stacks related functions and macros *
1078 * *
1079 ************************************************************************/
1080
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001081/**
1082 * valuePop:
1083 * @ctxt: an XPath evaluation context
1084 *
1085 * Pops the top XPath object from the value stack
1086 *
1087 * Returns the XPath object just removed
1088 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001089extern xmlXPathObjectPtr
1090valuePop(xmlXPathParserContextPtr ctxt)
1091{
1092 xmlXPathObjectPtr ret;
1093
1094 if (ctxt->valueNr <= 0)
1095 return (0);
1096 ctxt->valueNr--;
1097 if (ctxt->valueNr > 0)
1098 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1099 else
1100 ctxt->value = NULL;
1101 ret = ctxt->valueTab[ctxt->valueNr];
1102 ctxt->valueTab[ctxt->valueNr] = 0;
1103 return (ret);
1104}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001105/**
1106 * valuePush:
1107 * @ctxt: an XPath evaluation context
1108 * @value: the XPath object
1109 *
1110 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001111 *
1112 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001113 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001114extern int
1115valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1116{
1117 if (ctxt->valueNr >= ctxt->valueMax) {
1118 ctxt->valueMax *= 2;
1119 ctxt->valueTab =
1120 (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1121 ctxt->valueMax *
1122 sizeof(ctxt->valueTab[0]));
1123 if (ctxt->valueTab == NULL) {
1124 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1125 return (0);
1126 }
1127 }
1128 ctxt->valueTab[ctxt->valueNr] = value;
1129 ctxt->value = value;
1130 return (ctxt->valueNr++);
1131}
Owen Taylor3473f882001-02-23 17:55:21 +00001132
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001133/**
1134 * xmlXPathPopBoolean:
1135 * @ctxt: an XPath parser context
1136 *
1137 * Pops a boolean from the stack, handling conversion if needed.
1138 * Check error with #xmlXPathCheckError.
1139 *
1140 * Returns the boolean
1141 */
1142int
1143xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1144 xmlXPathObjectPtr obj;
1145 int ret;
1146
1147 obj = valuePop(ctxt);
1148 if (obj == NULL) {
1149 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1150 return(0);
1151 }
William M. Brack08171912003-12-29 02:52:11 +00001152 if (obj->type != XPATH_BOOLEAN)
1153 ret = xmlXPathCastToBoolean(obj);
1154 else
1155 ret = obj->boolval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001156 xmlXPathFreeObject(obj);
1157 return(ret);
1158}
1159
1160/**
1161 * xmlXPathPopNumber:
1162 * @ctxt: an XPath parser context
1163 *
1164 * Pops a number from the stack, handling conversion if needed.
1165 * Check error with #xmlXPathCheckError.
1166 *
1167 * Returns the number
1168 */
1169double
1170xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1171 xmlXPathObjectPtr obj;
1172 double ret;
1173
1174 obj = valuePop(ctxt);
1175 if (obj == NULL) {
1176 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1177 return(0);
1178 }
William M. Brack08171912003-12-29 02:52:11 +00001179 if (obj->type != XPATH_NUMBER)
1180 ret = xmlXPathCastToNumber(obj);
1181 else
1182 ret = obj->floatval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001183 xmlXPathFreeObject(obj);
1184 return(ret);
1185}
1186
1187/**
1188 * xmlXPathPopString:
1189 * @ctxt: an XPath parser context
1190 *
1191 * Pops a string from the stack, handling conversion if needed.
1192 * Check error with #xmlXPathCheckError.
1193 *
1194 * Returns the string
1195 */
1196xmlChar *
1197xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1198 xmlXPathObjectPtr obj;
1199 xmlChar * ret;
1200
1201 obj = valuePop(ctxt);
1202 if (obj == NULL) {
1203 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1204 return(NULL);
1205 }
William M. Brack08171912003-12-29 02:52:11 +00001206 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001207 /* TODO: needs refactoring somewhere else */
1208 if (obj->stringval == ret)
1209 obj->stringval = NULL;
1210 xmlXPathFreeObject(obj);
1211 return(ret);
1212}
1213
1214/**
1215 * xmlXPathPopNodeSet:
1216 * @ctxt: an XPath parser context
1217 *
1218 * Pops a node-set from the stack, handling conversion if needed.
1219 * Check error with #xmlXPathCheckError.
1220 *
1221 * Returns the node-set
1222 */
1223xmlNodeSetPtr
1224xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1225 xmlXPathObjectPtr obj;
1226 xmlNodeSetPtr ret;
1227
1228 if (ctxt->value == NULL) {
1229 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1230 return(NULL);
1231 }
1232 if (!xmlXPathStackIsNodeSet(ctxt)) {
1233 xmlXPathSetTypeError(ctxt);
1234 return(NULL);
1235 }
1236 obj = valuePop(ctxt);
1237 ret = obj->nodesetval;
Daniel Veillard9deb2422003-07-28 20:40:59 +00001238 /* to fix memory leak of not clearing obj->user */
1239 if (obj->boolval && obj->user != NULL)
1240 xmlFreeNodeList((xmlNodePtr) obj->user);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001241 xmlXPathFreeNodeSetList(obj);
1242 return(ret);
1243}
1244
1245/**
1246 * xmlXPathPopExternal:
1247 * @ctxt: an XPath parser context
1248 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001249 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001250 * Check error with #xmlXPathCheckError.
1251 *
1252 * Returns the object
1253 */
1254void *
1255xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1256 xmlXPathObjectPtr obj;
1257 void * ret;
1258
1259 if (ctxt->value == NULL) {
1260 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1261 return(NULL);
1262 }
1263 if (ctxt->value->type != XPATH_USERS) {
1264 xmlXPathSetTypeError(ctxt);
1265 return(NULL);
1266 }
1267 obj = valuePop(ctxt);
1268 ret = obj->user;
1269 xmlXPathFreeObject(obj);
1270 return(ret);
1271}
1272
Owen Taylor3473f882001-02-23 17:55:21 +00001273/*
1274 * Macros for accessing the content. Those should be used only by the parser,
1275 * and not exported.
1276 *
1277 * Dirty macros, i.e. one need to make assumption on the context to use them
1278 *
1279 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1280 * CUR returns the current xmlChar value, i.e. a 8 bit value
1281 * in ISO-Latin or UTF-8.
1282 * This should be used internally by the parser
1283 * only to compare to ASCII values otherwise it would break when
1284 * running with UTF-8 encoding.
1285 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1286 * to compare on ASCII based substring.
1287 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1288 * strings within the parser.
1289 * CURRENT Returns the current char value, with the full decoding of
1290 * UTF-8 if we are using this mode. It returns an int.
1291 * NEXT Skip to the next character, this does the proper decoding
1292 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1293 * It returns the pointer to the current xmlChar.
1294 */
1295
1296#define CUR (*ctxt->cur)
1297#define SKIP(val) ctxt->cur += (val)
1298#define NXT(val) ctxt->cur[(val)]
1299#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001300#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1301
1302#define COPY_BUF(l,b,i,v) \
1303 if (l == 1) b[i++] = (xmlChar) v; \
1304 else i += xmlCopyChar(l,&b[i],v)
1305
1306#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001307
1308#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001309 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001310
1311#define CURRENT (*ctxt->cur)
1312#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1313
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001314
1315#ifndef DBL_DIG
1316#define DBL_DIG 16
1317#endif
1318#ifndef DBL_EPSILON
1319#define DBL_EPSILON 1E-9
1320#endif
1321
1322#define UPPER_DOUBLE 1E9
1323#define LOWER_DOUBLE 1E-5
1324
1325#define INTEGER_DIGITS DBL_DIG
1326#define FRACTION_DIGITS (DBL_DIG + 1)
1327#define EXPONENT_DIGITS (3 + 2)
1328
1329/**
1330 * xmlXPathFormatNumber:
1331 * @number: number to format
1332 * @buffer: output buffer
1333 * @buffersize: size of output buffer
1334 *
1335 * Convert the number into a string representation.
1336 */
1337static void
1338xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1339{
Daniel Veillardcda96922001-08-21 10:56:31 +00001340 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001341 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001342 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001343 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001344 break;
1345 case -1:
1346 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001347 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001348 break;
1349 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001350 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001351 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001352 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001353 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001354 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001355 } else if (number == ((int) number)) {
1356 char work[30];
1357 char *ptr, *cur;
1358 int res, value = (int) number;
1359
1360 ptr = &buffer[0];
1361 if (value < 0) {
1362 *ptr++ = '-';
1363 value = -value;
1364 }
1365 if (value == 0) {
1366 *ptr++ = '0';
1367 } else {
1368 cur = &work[0];
1369 while (value != 0) {
1370 res = value % 10;
1371 value = value / 10;
1372 *cur++ = '0' + res;
1373 }
1374 cur--;
1375 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1376 *ptr++ = *cur--;
1377 }
1378 }
1379 if (ptr - buffer < buffersize) {
1380 *ptr = 0;
1381 } else if (buffersize > 0) {
1382 ptr--;
1383 *ptr = 0;
1384 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001385 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001386 /* 3 is sign, decimal point, and terminating zero */
1387 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1388 int integer_place, fraction_place;
1389 char *ptr;
1390 char *after_fraction;
1391 double absolute_value;
1392 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001393
Bjorn Reese70a9da52001-04-21 16:57:29 +00001394 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001395
Bjorn Reese70a9da52001-04-21 16:57:29 +00001396 /*
1397 * First choose format - scientific or regular floating point.
1398 * In either case, result is in work, and after_fraction points
1399 * just past the fractional part.
1400 */
1401 if ( ((absolute_value > UPPER_DOUBLE) ||
1402 (absolute_value < LOWER_DOUBLE)) &&
1403 (absolute_value != 0.0) ) {
1404 /* Use scientific notation */
1405 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1406 fraction_place = DBL_DIG - 1;
1407 snprintf(work, sizeof(work),"%*.*e",
1408 integer_place, fraction_place, number);
1409 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001410 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001411 else {
1412 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001413 if (absolute_value > 0.0)
1414 integer_place = 1 + (int)log10(absolute_value);
1415 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001416 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001417 fraction_place = (integer_place > 0)
1418 ? DBL_DIG - integer_place
1419 : DBL_DIG;
1420 size = snprintf(work, sizeof(work), "%0.*f",
1421 fraction_place, number);
1422 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001423 }
1424
Bjorn Reese70a9da52001-04-21 16:57:29 +00001425 /* Remove fractional trailing zeroes */
1426 ptr = after_fraction;
1427 while (*(--ptr) == '0')
1428 ;
1429 if (*ptr != '.')
1430 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001431 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001432
1433 /* Finally copy result back to caller */
1434 size = strlen(work) + 1;
1435 if (size > buffersize) {
1436 work[buffersize - 1] = 0;
1437 size = buffersize;
1438 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001439 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001440 }
1441 break;
1442 }
1443}
1444
Owen Taylor3473f882001-02-23 17:55:21 +00001445
1446/************************************************************************
1447 * *
1448 * Routines to handle NodeSets *
1449 * *
1450 ************************************************************************/
1451
1452/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001453 * xmlXPathOrderDocElems:
1454 * @doc: an input document
1455 *
1456 * Call this routine to speed up XPath computation on static documents.
1457 * This stamps all the element nodes with the document order
1458 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00001459 * field, the value stored is actually - the node number (starting at -1)
1460 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001461 *
William M. Brack08171912003-12-29 02:52:11 +00001462 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001463 * of error.
1464 */
1465long
1466xmlXPathOrderDocElems(xmlDocPtr doc) {
1467 long count = 0;
1468 xmlNodePtr cur;
1469
1470 if (doc == NULL)
1471 return(-1);
1472 cur = doc->children;
1473 while (cur != NULL) {
1474 if (cur->type == XML_ELEMENT_NODE) {
1475 cur->content = (void *) (-(++count));
1476 if (cur->children != NULL) {
1477 cur = cur->children;
1478 continue;
1479 }
1480 }
1481 if (cur->next != NULL) {
1482 cur = cur->next;
1483 continue;
1484 }
1485 do {
1486 cur = cur->parent;
1487 if (cur == NULL)
1488 break;
1489 if (cur == (xmlNodePtr) doc) {
1490 cur = NULL;
1491 break;
1492 }
1493 if (cur->next != NULL) {
1494 cur = cur->next;
1495 break;
1496 }
1497 } while (cur != NULL);
1498 }
1499 return(count);
1500}
1501
1502/**
Owen Taylor3473f882001-02-23 17:55:21 +00001503 * xmlXPathCmpNodes:
1504 * @node1: the first node
1505 * @node2: the second node
1506 *
1507 * Compare two nodes w.r.t document order
1508 *
1509 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00001510 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001511 */
1512int
1513xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1514 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001515 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001516 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001517 xmlNodePtr cur, root;
1518
1519 if ((node1 == NULL) || (node2 == NULL))
1520 return(-2);
1521 /*
1522 * a couple of optimizations which will avoid computations in most cases
1523 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001524 if (node1->type == XML_ATTRIBUTE_NODE) {
1525 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001526 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001527 node1 = node1->parent;
1528 }
1529 if (node2->type == XML_ATTRIBUTE_NODE) {
1530 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001531 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001532 node2 = node2->parent;
1533 }
1534 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001535 if (attr1 == attr2) {
1536 /* not required, but we keep attributes in order */
1537 if (attr1 != 0) {
1538 cur = attrNode2->prev;
1539 while (cur != NULL) {
1540 if (cur == attrNode1)
1541 return (1);
1542 cur = cur->prev;
1543 }
1544 return (-1);
1545 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001546 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001547 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001548 if (attr2 == 1)
1549 return(1);
1550 return(-1);
1551 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001552 if ((node1->type == XML_NAMESPACE_DECL) ||
1553 (node2->type == XML_NAMESPACE_DECL))
1554 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001555 if (node1 == node2->prev)
1556 return(1);
1557 if (node1 == node2->next)
1558 return(-1);
1559
1560 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001561 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001562 */
1563 if ((node1->type == XML_ELEMENT_NODE) &&
1564 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001565 (0 > (long) node1->content) &&
1566 (0 > (long) node2->content) &&
1567 (node1->doc == node2->doc)) {
1568 long l1, l2;
1569
1570 l1 = -((long) node1->content);
1571 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001572 if (l1 < l2)
1573 return(1);
1574 if (l1 > l2)
1575 return(-1);
1576 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001577
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001578 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001579 * compute depth to root
1580 */
1581 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1582 if (cur == node1)
1583 return(1);
1584 depth2++;
1585 }
1586 root = cur;
1587 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1588 if (cur == node2)
1589 return(-1);
1590 depth1++;
1591 }
1592 /*
1593 * Distinct document (or distinct entities :-( ) case.
1594 */
1595 if (root != cur) {
1596 return(-2);
1597 }
1598 /*
1599 * get the nearest common ancestor.
1600 */
1601 while (depth1 > depth2) {
1602 depth1--;
1603 node1 = node1->parent;
1604 }
1605 while (depth2 > depth1) {
1606 depth2--;
1607 node2 = node2->parent;
1608 }
1609 while (node1->parent != node2->parent) {
1610 node1 = node1->parent;
1611 node2 = node2->parent;
1612 /* should not happen but just in case ... */
1613 if ((node1 == NULL) || (node2 == NULL))
1614 return(-2);
1615 }
1616 /*
1617 * Find who's first.
1618 */
Daniel Veillardf49be472004-02-17 11:48:18 +00001619 if (node1 == node2->prev)
1620 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001621 if (node1 == node2->next)
1622 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00001623 /*
1624 * Speedup using document order if availble.
1625 */
1626 if ((node1->type == XML_ELEMENT_NODE) &&
1627 (node2->type == XML_ELEMENT_NODE) &&
1628 (0 > (long) node1->content) &&
1629 (0 > (long) node2->content) &&
1630 (node1->doc == node2->doc)) {
1631 long l1, l2;
1632
1633 l1 = -((long) node1->content);
1634 l2 = -((long) node2->content);
1635 if (l1 < l2)
1636 return(1);
1637 if (l1 > l2)
1638 return(-1);
1639 }
1640
Owen Taylor3473f882001-02-23 17:55:21 +00001641 for (cur = node1->next;cur != NULL;cur = cur->next)
1642 if (cur == node2)
1643 return(1);
1644 return(-1); /* assume there is no sibling list corruption */
1645}
1646
1647/**
1648 * xmlXPathNodeSetSort:
1649 * @set: the node set
1650 *
1651 * Sort the node set in document order
1652 */
1653void
1654xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001655 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001656 xmlNodePtr tmp;
1657
1658 if (set == NULL)
1659 return;
1660
1661 /* Use Shell's sort to sort the node-set */
1662 len = set->nodeNr;
1663 for (incr = len / 2; incr > 0; incr /= 2) {
1664 for (i = incr; i < len; i++) {
1665 j = i - incr;
1666 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001667 if (xmlXPathCmpNodes(set->nodeTab[j],
1668 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001669 tmp = set->nodeTab[j];
1670 set->nodeTab[j] = set->nodeTab[j + incr];
1671 set->nodeTab[j + incr] = tmp;
1672 j -= incr;
1673 } else
1674 break;
1675 }
1676 }
1677 }
1678}
1679
1680#define XML_NODESET_DEFAULT 10
1681/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001682 * xmlXPathNodeSetDupNs:
1683 * @node: the parent node of the namespace XPath node
1684 * @ns: the libxml namespace declaration node.
1685 *
1686 * Namespace node in libxml don't match the XPath semantic. In a node set
1687 * the namespace nodes are duplicated and the next pointer is set to the
1688 * parent node in the XPath semantic.
1689 *
1690 * Returns the newly created object.
1691 */
1692static xmlNodePtr
1693xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1694 xmlNsPtr cur;
1695
1696 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1697 return(NULL);
1698 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1699 return((xmlNodePtr) ns);
1700
1701 /*
1702 * Allocate a new Namespace and fill the fields.
1703 */
1704 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1705 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001706 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001707 return(NULL);
1708 }
1709 memset(cur, 0, sizeof(xmlNs));
1710 cur->type = XML_NAMESPACE_DECL;
1711 if (ns->href != NULL)
1712 cur->href = xmlStrdup(ns->href);
1713 if (ns->prefix != NULL)
1714 cur->prefix = xmlStrdup(ns->prefix);
1715 cur->next = (xmlNsPtr) node;
1716 return((xmlNodePtr) cur);
1717}
1718
1719/**
1720 * xmlXPathNodeSetFreeNs:
1721 * @ns: the XPath namespace node found in a nodeset.
1722 *
William M. Brack08171912003-12-29 02:52:11 +00001723 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001724 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00001725 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001726 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001727void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001728xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1729 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1730 return;
1731
1732 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1733 if (ns->href != NULL)
1734 xmlFree((xmlChar *)ns->href);
1735 if (ns->prefix != NULL)
1736 xmlFree((xmlChar *)ns->prefix);
1737 xmlFree(ns);
1738 }
1739}
1740
1741/**
Owen Taylor3473f882001-02-23 17:55:21 +00001742 * xmlXPathNodeSetCreate:
1743 * @val: an initial xmlNodePtr, or NULL
1744 *
1745 * Create a new xmlNodeSetPtr of type double and of value @val
1746 *
1747 * Returns the newly created object.
1748 */
1749xmlNodeSetPtr
1750xmlXPathNodeSetCreate(xmlNodePtr val) {
1751 xmlNodeSetPtr ret;
1752
1753 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1754 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001755 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001756 return(NULL);
1757 }
1758 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1759 if (val != NULL) {
1760 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1761 sizeof(xmlNodePtr));
1762 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001763 xmlXPathErrMemory(NULL, "creating nodeset\n");
1764 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001765 return(NULL);
1766 }
1767 memset(ret->nodeTab, 0 ,
1768 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1769 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001770 if (val->type == XML_NAMESPACE_DECL) {
1771 xmlNsPtr ns = (xmlNsPtr) val;
1772
1773 ret->nodeTab[ret->nodeNr++] =
1774 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1775 } else
1776 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001777 }
1778 return(ret);
1779}
1780
1781/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001782 * xmlXPathNodeSetContains:
1783 * @cur: the node-set
1784 * @val: the node
1785 *
1786 * checks whether @cur contains @val
1787 *
1788 * Returns true (1) if @cur contains @val, false (0) otherwise
1789 */
1790int
1791xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1792 int i;
1793
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001794 if (val->type == XML_NAMESPACE_DECL) {
1795 for (i = 0; i < cur->nodeNr; i++) {
1796 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1797 xmlNsPtr ns1, ns2;
1798
1799 ns1 = (xmlNsPtr) val;
1800 ns2 = (xmlNsPtr) cur->nodeTab[i];
1801 if (ns1 == ns2)
1802 return(1);
1803 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1804 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1805 return(1);
1806 }
1807 }
1808 } else {
1809 for (i = 0; i < cur->nodeNr; i++) {
1810 if (cur->nodeTab[i] == val)
1811 return(1);
1812 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001813 }
1814 return(0);
1815}
1816
1817/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001818 * xmlXPathNodeSetAddNs:
1819 * @cur: the initial node set
1820 * @node: the hosting node
1821 * @ns: a the namespace node
1822 *
1823 * add a new namespace node to an existing NodeSet
1824 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001825void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001826xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1827 int i;
1828
1829 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1830 (node->type != XML_ELEMENT_NODE))
1831 return;
1832
William M. Brack08171912003-12-29 02:52:11 +00001833 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001834 /*
William M. Brack08171912003-12-29 02:52:11 +00001835 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001836 */
1837 for (i = 0;i < cur->nodeNr;i++) {
1838 if ((cur->nodeTab[i] != NULL) &&
1839 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001840 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001841 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1842 return;
1843 }
1844
1845 /*
1846 * grow the nodeTab if needed
1847 */
1848 if (cur->nodeMax == 0) {
1849 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1850 sizeof(xmlNodePtr));
1851 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001852 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001853 return;
1854 }
1855 memset(cur->nodeTab, 0 ,
1856 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1857 cur->nodeMax = XML_NODESET_DEFAULT;
1858 } else if (cur->nodeNr == cur->nodeMax) {
1859 xmlNodePtr *temp;
1860
1861 cur->nodeMax *= 2;
1862 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1863 sizeof(xmlNodePtr));
1864 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001865 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001866 return;
1867 }
1868 cur->nodeTab = temp;
1869 }
1870 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1871}
1872
1873/**
Owen Taylor3473f882001-02-23 17:55:21 +00001874 * xmlXPathNodeSetAdd:
1875 * @cur: the initial node set
1876 * @val: a new xmlNodePtr
1877 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001878 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001879 */
1880void
1881xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1882 int i;
1883
1884 if (val == NULL) return;
1885
Daniel Veillardef0b4502003-03-24 13:57:34 +00001886#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001887 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1888 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001889#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001890
William M. Brack08171912003-12-29 02:52:11 +00001891 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001892 /*
William M. Brack08171912003-12-29 02:52:11 +00001893 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00001894 */
1895 for (i = 0;i < cur->nodeNr;i++)
1896 if (cur->nodeTab[i] == val) return;
1897
1898 /*
1899 * grow the nodeTab if needed
1900 */
1901 if (cur->nodeMax == 0) {
1902 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1903 sizeof(xmlNodePtr));
1904 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001905 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001906 return;
1907 }
1908 memset(cur->nodeTab, 0 ,
1909 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1910 cur->nodeMax = XML_NODESET_DEFAULT;
1911 } else if (cur->nodeNr == cur->nodeMax) {
1912 xmlNodePtr *temp;
1913
1914 cur->nodeMax *= 2;
1915 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1916 sizeof(xmlNodePtr));
1917 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001918 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001919 return;
1920 }
1921 cur->nodeTab = temp;
1922 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001923 if (val->type == XML_NAMESPACE_DECL) {
1924 xmlNsPtr ns = (xmlNsPtr) val;
1925
1926 cur->nodeTab[cur->nodeNr++] =
1927 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1928 } else
1929 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001930}
1931
1932/**
1933 * xmlXPathNodeSetAddUnique:
1934 * @cur: the initial node set
1935 * @val: a new xmlNodePtr
1936 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001937 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001938 * when we are sure the node is not already in the set.
1939 */
1940void
1941xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1942 if (val == NULL) return;
1943
Daniel Veillardef0b4502003-03-24 13:57:34 +00001944#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001945 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1946 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001947#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001948
William M. Brack08171912003-12-29 02:52:11 +00001949 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001950 /*
1951 * grow the nodeTab if needed
1952 */
1953 if (cur->nodeMax == 0) {
1954 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1955 sizeof(xmlNodePtr));
1956 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001957 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001958 return;
1959 }
1960 memset(cur->nodeTab, 0 ,
1961 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1962 cur->nodeMax = XML_NODESET_DEFAULT;
1963 } else if (cur->nodeNr == cur->nodeMax) {
1964 xmlNodePtr *temp;
1965
1966 cur->nodeMax *= 2;
1967 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1968 sizeof(xmlNodePtr));
1969 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001970 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001971 return;
1972 }
1973 cur->nodeTab = temp;
1974 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001975 if (val->type == XML_NAMESPACE_DECL) {
1976 xmlNsPtr ns = (xmlNsPtr) val;
1977
1978 cur->nodeTab[cur->nodeNr++] =
1979 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1980 } else
1981 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001982}
1983
1984/**
1985 * xmlXPathNodeSetMerge:
1986 * @val1: the first NodeSet or NULL
1987 * @val2: the second NodeSet
1988 *
1989 * Merges two nodesets, all nodes from @val2 are added to @val1
1990 * if @val1 is NULL, a new set is created and copied from @val2
1991 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001992 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001993 */
1994xmlNodeSetPtr
1995xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001996 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001997
1998 if (val2 == NULL) return(val1);
1999 if (val1 == NULL) {
2000 val1 = xmlXPathNodeSetCreate(NULL);
2001 }
2002
William M. Brack08171912003-12-29 02:52:11 +00002003 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002004 initNr = val1->nodeNr;
2005
2006 for (i = 0;i < val2->nodeNr;i++) {
2007 /*
William M. Brack08171912003-12-29 02:52:11 +00002008 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00002009 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002010 skip = 0;
2011 for (j = 0; j < initNr; j++) {
2012 if (val1->nodeTab[j] == val2->nodeTab[i]) {
2013 skip = 1;
2014 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002015 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
2016 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
2017 xmlNsPtr ns1, ns2;
2018 ns1 = (xmlNsPtr) val1->nodeTab[j];
2019 ns2 = (xmlNsPtr) val2->nodeTab[i];
2020 if ((ns1->next == ns2->next) &&
2021 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
2022 skip = 1;
2023 break;
2024 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002025 }
2026 }
2027 if (skip)
2028 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00002029
2030 /*
2031 * grow the nodeTab if needed
2032 */
2033 if (val1->nodeMax == 0) {
2034 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2035 sizeof(xmlNodePtr));
2036 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002037 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002038 return(NULL);
2039 }
2040 memset(val1->nodeTab, 0 ,
2041 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2042 val1->nodeMax = XML_NODESET_DEFAULT;
2043 } else if (val1->nodeNr == val1->nodeMax) {
2044 xmlNodePtr *temp;
2045
2046 val1->nodeMax *= 2;
2047 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2048 sizeof(xmlNodePtr));
2049 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002050 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002051 return(NULL);
2052 }
2053 val1->nodeTab = temp;
2054 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002055 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2056 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2057
2058 val1->nodeTab[val1->nodeNr++] =
2059 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2060 } else
2061 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002062 }
2063
2064 return(val1);
2065}
2066
2067/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002068 * xmlXPathNodeSetMergeUnique:
2069 * @val1: the first NodeSet or NULL
2070 * @val2: the second NodeSet
2071 *
2072 * Merges two nodesets, all nodes from @val2 are added to @val1
2073 * if @val1 is NULL, a new set is created and copied from @val2
2074 *
2075 * Returns @val1 once extended or NULL in case of error.
2076 */
2077static xmlNodeSetPtr
2078xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002079 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002080
2081 if (val2 == NULL) return(val1);
2082 if (val1 == NULL) {
2083 val1 = xmlXPathNodeSetCreate(NULL);
2084 }
2085
William M. Brack08171912003-12-29 02:52:11 +00002086 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002087
2088 for (i = 0;i < val2->nodeNr;i++) {
2089 /*
2090 * grow the nodeTab if needed
2091 */
2092 if (val1->nodeMax == 0) {
2093 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2094 sizeof(xmlNodePtr));
2095 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002096 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002097 return(NULL);
2098 }
2099 memset(val1->nodeTab, 0 ,
2100 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2101 val1->nodeMax = XML_NODESET_DEFAULT;
2102 } else if (val1->nodeNr == val1->nodeMax) {
2103 xmlNodePtr *temp;
2104
2105 val1->nodeMax *= 2;
2106 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2107 sizeof(xmlNodePtr));
2108 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002109 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002110 return(NULL);
2111 }
2112 val1->nodeTab = temp;
2113 }
2114 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2115 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2116
2117 val1->nodeTab[val1->nodeNr++] =
2118 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2119 } else
2120 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2121 }
2122
2123 return(val1);
2124}
2125
2126/**
Owen Taylor3473f882001-02-23 17:55:21 +00002127 * xmlXPathNodeSetDel:
2128 * @cur: the initial node set
2129 * @val: an xmlNodePtr
2130 *
2131 * Removes an xmlNodePtr from an existing NodeSet
2132 */
2133void
2134xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2135 int i;
2136
2137 if (cur == NULL) return;
2138 if (val == NULL) return;
2139
2140 /*
William M. Brack08171912003-12-29 02:52:11 +00002141 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002142 */
2143 for (i = 0;i < cur->nodeNr;i++)
2144 if (cur->nodeTab[i] == val) break;
2145
William M. Brack08171912003-12-29 02:52:11 +00002146 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002147#ifdef DEBUG
2148 xmlGenericError(xmlGenericErrorContext,
2149 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2150 val->name);
2151#endif
2152 return;
2153 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002154 if ((cur->nodeTab[i] != NULL) &&
2155 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2156 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002157 cur->nodeNr--;
2158 for (;i < cur->nodeNr;i++)
2159 cur->nodeTab[i] = cur->nodeTab[i + 1];
2160 cur->nodeTab[cur->nodeNr] = NULL;
2161}
2162
2163/**
2164 * xmlXPathNodeSetRemove:
2165 * @cur: the initial node set
2166 * @val: the index to remove
2167 *
2168 * Removes an entry from an existing NodeSet list.
2169 */
2170void
2171xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2172 if (cur == NULL) return;
2173 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002174 if ((cur->nodeTab[val] != NULL) &&
2175 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2176 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002177 cur->nodeNr--;
2178 for (;val < cur->nodeNr;val++)
2179 cur->nodeTab[val] = cur->nodeTab[val + 1];
2180 cur->nodeTab[cur->nodeNr] = NULL;
2181}
2182
2183/**
2184 * xmlXPathFreeNodeSet:
2185 * @obj: the xmlNodeSetPtr to free
2186 *
2187 * Free the NodeSet compound (not the actual nodes !).
2188 */
2189void
2190xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2191 if (obj == NULL) return;
2192 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002193 int i;
2194
William M. Brack08171912003-12-29 02:52:11 +00002195 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002196 for (i = 0;i < obj->nodeNr;i++)
2197 if ((obj->nodeTab[i] != NULL) &&
2198 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2199 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002200 xmlFree(obj->nodeTab);
2201 }
Owen Taylor3473f882001-02-23 17:55:21 +00002202 xmlFree(obj);
2203}
2204
2205/**
2206 * xmlXPathFreeValueTree:
2207 * @obj: the xmlNodeSetPtr to free
2208 *
2209 * Free the NodeSet compound and the actual tree, this is different
2210 * from xmlXPathFreeNodeSet()
2211 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002212static void
Owen Taylor3473f882001-02-23 17:55:21 +00002213xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2214 int i;
2215
2216 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002217
2218 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002219 for (i = 0;i < obj->nodeNr;i++) {
2220 if (obj->nodeTab[i] != NULL) {
2221 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2222 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2223 } else {
2224 xmlFreeNodeList(obj->nodeTab[i]);
2225 }
2226 }
2227 }
Owen Taylor3473f882001-02-23 17:55:21 +00002228 xmlFree(obj->nodeTab);
2229 }
Owen Taylor3473f882001-02-23 17:55:21 +00002230 xmlFree(obj);
2231}
2232
2233#if defined(DEBUG) || defined(DEBUG_STEP)
2234/**
2235 * xmlGenericErrorContextNodeSet:
2236 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002237 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002238 *
2239 * Quick display of a NodeSet
2240 */
2241void
2242xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2243 int i;
2244
2245 if (output == NULL) output = xmlGenericErrorContext;
2246 if (obj == NULL) {
2247 fprintf(output, "NodeSet == NULL !\n");
2248 return;
2249 }
2250 if (obj->nodeNr == 0) {
2251 fprintf(output, "NodeSet is empty\n");
2252 return;
2253 }
2254 if (obj->nodeTab == NULL) {
2255 fprintf(output, " nodeTab == NULL !\n");
2256 return;
2257 }
2258 for (i = 0; i < obj->nodeNr; i++) {
2259 if (obj->nodeTab[i] == NULL) {
2260 fprintf(output, " NULL !\n");
2261 return;
2262 }
2263 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2264 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2265 fprintf(output, " /");
2266 else if (obj->nodeTab[i]->name == NULL)
2267 fprintf(output, " noname!");
2268 else fprintf(output, " %s", obj->nodeTab[i]->name);
2269 }
2270 fprintf(output, "\n");
2271}
2272#endif
2273
2274/**
2275 * xmlXPathNewNodeSet:
2276 * @val: the NodePtr value
2277 *
2278 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2279 * it with the single Node @val
2280 *
2281 * Returns the newly created object.
2282 */
2283xmlXPathObjectPtr
2284xmlXPathNewNodeSet(xmlNodePtr val) {
2285 xmlXPathObjectPtr ret;
2286
2287 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2288 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002289 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002290 return(NULL);
2291 }
2292 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2293 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002294 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002295 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002296 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002297 return(ret);
2298}
2299
2300/**
2301 * xmlXPathNewValueTree:
2302 * @val: the NodePtr value
2303 *
2304 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2305 * it with the tree root @val
2306 *
2307 * Returns the newly created object.
2308 */
2309xmlXPathObjectPtr
2310xmlXPathNewValueTree(xmlNodePtr val) {
2311 xmlXPathObjectPtr ret;
2312
2313 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2314 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002315 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002316 return(NULL);
2317 }
2318 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2319 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002320 ret->boolval = 1;
2321 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002322 ret->nodesetval = xmlXPathNodeSetCreate(val);
2323 return(ret);
2324}
2325
2326/**
2327 * xmlXPathNewNodeSetList:
2328 * @val: an existing NodeSet
2329 *
2330 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2331 * it with the Nodeset @val
2332 *
2333 * Returns the newly created object.
2334 */
2335xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002336xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2337{
Owen Taylor3473f882001-02-23 17:55:21 +00002338 xmlXPathObjectPtr ret;
2339 int i;
2340
2341 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002342 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002343 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002344 ret = xmlXPathNewNodeSet(NULL);
2345 else {
2346 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2347 for (i = 1; i < val->nodeNr; ++i)
2348 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2349 }
Owen Taylor3473f882001-02-23 17:55:21 +00002350
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002351 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002352}
2353
2354/**
2355 * xmlXPathWrapNodeSet:
2356 * @val: the NodePtr value
2357 *
2358 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2359 *
2360 * Returns the newly created object.
2361 */
2362xmlXPathObjectPtr
2363xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2364 xmlXPathObjectPtr ret;
2365
2366 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2367 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002368 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002369 return(NULL);
2370 }
2371 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2372 ret->type = XPATH_NODESET;
2373 ret->nodesetval = val;
2374 return(ret);
2375}
2376
2377/**
2378 * xmlXPathFreeNodeSetList:
2379 * @obj: an existing NodeSetList object
2380 *
2381 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2382 * the list contrary to xmlXPathFreeObject().
2383 */
2384void
2385xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2386 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002387 xmlFree(obj);
2388}
2389
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002390/**
2391 * xmlXPathDifference:
2392 * @nodes1: a node-set
2393 * @nodes2: a node-set
2394 *
2395 * Implements the EXSLT - Sets difference() function:
2396 * node-set set:difference (node-set, node-set)
2397 *
2398 * Returns the difference between the two node sets, or nodes1 if
2399 * nodes2 is empty
2400 */
2401xmlNodeSetPtr
2402xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2403 xmlNodeSetPtr ret;
2404 int i, l1;
2405 xmlNodePtr cur;
2406
2407 if (xmlXPathNodeSetIsEmpty(nodes2))
2408 return(nodes1);
2409
2410 ret = xmlXPathNodeSetCreate(NULL);
2411 if (xmlXPathNodeSetIsEmpty(nodes1))
2412 return(ret);
2413
2414 l1 = xmlXPathNodeSetGetLength(nodes1);
2415
2416 for (i = 0; i < l1; i++) {
2417 cur = xmlXPathNodeSetItem(nodes1, i);
2418 if (!xmlXPathNodeSetContains(nodes2, cur))
2419 xmlXPathNodeSetAddUnique(ret, cur);
2420 }
2421 return(ret);
2422}
2423
2424/**
2425 * xmlXPathIntersection:
2426 * @nodes1: a node-set
2427 * @nodes2: a node-set
2428 *
2429 * Implements the EXSLT - Sets intersection() function:
2430 * node-set set:intersection (node-set, node-set)
2431 *
2432 * Returns a node set comprising the nodes that are within both the
2433 * node sets passed as arguments
2434 */
2435xmlNodeSetPtr
2436xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2437 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2438 int i, l1;
2439 xmlNodePtr cur;
2440
2441 if (xmlXPathNodeSetIsEmpty(nodes1))
2442 return(ret);
2443 if (xmlXPathNodeSetIsEmpty(nodes2))
2444 return(ret);
2445
2446 l1 = xmlXPathNodeSetGetLength(nodes1);
2447
2448 for (i = 0; i < l1; i++) {
2449 cur = xmlXPathNodeSetItem(nodes1, i);
2450 if (xmlXPathNodeSetContains(nodes2, cur))
2451 xmlXPathNodeSetAddUnique(ret, cur);
2452 }
2453 return(ret);
2454}
2455
2456/**
2457 * xmlXPathDistinctSorted:
2458 * @nodes: a node-set, sorted by document order
2459 *
2460 * Implements the EXSLT - Sets distinct() function:
2461 * node-set set:distinct (node-set)
2462 *
2463 * Returns a subset of the nodes contained in @nodes, or @nodes if
2464 * it is empty
2465 */
2466xmlNodeSetPtr
2467xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2468 xmlNodeSetPtr ret;
2469 xmlHashTablePtr hash;
2470 int i, l;
2471 xmlChar * strval;
2472 xmlNodePtr cur;
2473
2474 if (xmlXPathNodeSetIsEmpty(nodes))
2475 return(nodes);
2476
2477 ret = xmlXPathNodeSetCreate(NULL);
2478 l = xmlXPathNodeSetGetLength(nodes);
2479 hash = xmlHashCreate (l);
2480 for (i = 0; i < l; i++) {
2481 cur = xmlXPathNodeSetItem(nodes, i);
2482 strval = xmlXPathCastNodeToString(cur);
2483 if (xmlHashLookup(hash, strval) == NULL) {
2484 xmlHashAddEntry(hash, strval, strval);
2485 xmlXPathNodeSetAddUnique(ret, cur);
2486 } else {
2487 xmlFree(strval);
2488 }
2489 }
2490 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2491 return(ret);
2492}
2493
2494/**
2495 * xmlXPathDistinct:
2496 * @nodes: a node-set
2497 *
2498 * Implements the EXSLT - Sets distinct() function:
2499 * node-set set:distinct (node-set)
2500 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2501 * is called with the sorted node-set
2502 *
2503 * Returns a subset of the nodes contained in @nodes, or @nodes if
2504 * it is empty
2505 */
2506xmlNodeSetPtr
2507xmlXPathDistinct (xmlNodeSetPtr nodes) {
2508 if (xmlXPathNodeSetIsEmpty(nodes))
2509 return(nodes);
2510
2511 xmlXPathNodeSetSort(nodes);
2512 return(xmlXPathDistinctSorted(nodes));
2513}
2514
2515/**
2516 * xmlXPathHasSameNodes:
2517 * @nodes1: a node-set
2518 * @nodes2: a node-set
2519 *
2520 * Implements the EXSLT - Sets has-same-nodes function:
2521 * boolean set:has-same-node(node-set, node-set)
2522 *
2523 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2524 * otherwise
2525 */
2526int
2527xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2528 int i, l;
2529 xmlNodePtr cur;
2530
2531 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2532 xmlXPathNodeSetIsEmpty(nodes2))
2533 return(0);
2534
2535 l = xmlXPathNodeSetGetLength(nodes1);
2536 for (i = 0; i < l; i++) {
2537 cur = xmlXPathNodeSetItem(nodes1, i);
2538 if (xmlXPathNodeSetContains(nodes2, cur))
2539 return(1);
2540 }
2541 return(0);
2542}
2543
2544/**
2545 * xmlXPathNodeLeadingSorted:
2546 * @nodes: a node-set, sorted by document order
2547 * @node: a node
2548 *
2549 * Implements the EXSLT - Sets leading() function:
2550 * node-set set:leading (node-set, node-set)
2551 *
2552 * Returns the nodes in @nodes that precede @node in document order,
2553 * @nodes if @node is NULL or an empty node-set if @nodes
2554 * doesn't contain @node
2555 */
2556xmlNodeSetPtr
2557xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2558 int i, l;
2559 xmlNodePtr cur;
2560 xmlNodeSetPtr ret;
2561
2562 if (node == NULL)
2563 return(nodes);
2564
2565 ret = xmlXPathNodeSetCreate(NULL);
2566 if (xmlXPathNodeSetIsEmpty(nodes) ||
2567 (!xmlXPathNodeSetContains(nodes, node)))
2568 return(ret);
2569
2570 l = xmlXPathNodeSetGetLength(nodes);
2571 for (i = 0; i < l; i++) {
2572 cur = xmlXPathNodeSetItem(nodes, i);
2573 if (cur == node)
2574 break;
2575 xmlXPathNodeSetAddUnique(ret, cur);
2576 }
2577 return(ret);
2578}
2579
2580/**
2581 * xmlXPathNodeLeading:
2582 * @nodes: a node-set
2583 * @node: a node
2584 *
2585 * Implements the EXSLT - Sets leading() function:
2586 * node-set set:leading (node-set, node-set)
2587 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2588 * is called.
2589 *
2590 * Returns the nodes in @nodes that precede @node in document order,
2591 * @nodes if @node is NULL or an empty node-set if @nodes
2592 * doesn't contain @node
2593 */
2594xmlNodeSetPtr
2595xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2596 xmlXPathNodeSetSort(nodes);
2597 return(xmlXPathNodeLeadingSorted(nodes, node));
2598}
2599
2600/**
2601 * xmlXPathLeadingSorted:
2602 * @nodes1: a node-set, sorted by document order
2603 * @nodes2: a node-set, sorted by document order
2604 *
2605 * Implements the EXSLT - Sets leading() function:
2606 * node-set set:leading (node-set, node-set)
2607 *
2608 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2609 * in document order, @nodes1 if @nodes2 is NULL or empty or
2610 * an empty node-set if @nodes1 doesn't contain @nodes2
2611 */
2612xmlNodeSetPtr
2613xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2614 if (xmlXPathNodeSetIsEmpty(nodes2))
2615 return(nodes1);
2616 return(xmlXPathNodeLeadingSorted(nodes1,
2617 xmlXPathNodeSetItem(nodes2, 1)));
2618}
2619
2620/**
2621 * xmlXPathLeading:
2622 * @nodes1: a node-set
2623 * @nodes2: a node-set
2624 *
2625 * Implements the EXSLT - Sets leading() function:
2626 * node-set set:leading (node-set, node-set)
2627 * @nodes1 and @nodes2 are sorted by document order, then
2628 * #exslSetsLeadingSorted is called.
2629 *
2630 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2631 * in document order, @nodes1 if @nodes2 is NULL or empty or
2632 * an empty node-set if @nodes1 doesn't contain @nodes2
2633 */
2634xmlNodeSetPtr
2635xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2636 if (xmlXPathNodeSetIsEmpty(nodes2))
2637 return(nodes1);
2638 if (xmlXPathNodeSetIsEmpty(nodes1))
2639 return(xmlXPathNodeSetCreate(NULL));
2640 xmlXPathNodeSetSort(nodes1);
2641 xmlXPathNodeSetSort(nodes2);
2642 return(xmlXPathNodeLeadingSorted(nodes1,
2643 xmlXPathNodeSetItem(nodes2, 1)));
2644}
2645
2646/**
2647 * xmlXPathNodeTrailingSorted:
2648 * @nodes: a node-set, sorted by document order
2649 * @node: a node
2650 *
2651 * Implements the EXSLT - Sets trailing() function:
2652 * node-set set:trailing (node-set, node-set)
2653 *
2654 * Returns the nodes in @nodes that follow @node in document order,
2655 * @nodes if @node is NULL or an empty node-set if @nodes
2656 * doesn't contain @node
2657 */
2658xmlNodeSetPtr
2659xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2660 int i, l;
2661 xmlNodePtr cur;
2662 xmlNodeSetPtr ret;
2663
2664 if (node == NULL)
2665 return(nodes);
2666
2667 ret = xmlXPathNodeSetCreate(NULL);
2668 if (xmlXPathNodeSetIsEmpty(nodes) ||
2669 (!xmlXPathNodeSetContains(nodes, node)))
2670 return(ret);
2671
2672 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002673 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002674 cur = xmlXPathNodeSetItem(nodes, i);
2675 if (cur == node)
2676 break;
2677 xmlXPathNodeSetAddUnique(ret, cur);
2678 }
2679 return(ret);
2680}
2681
2682/**
2683 * xmlXPathNodeTrailing:
2684 * @nodes: a node-set
2685 * @node: a node
2686 *
2687 * Implements the EXSLT - Sets trailing() function:
2688 * node-set set:trailing (node-set, node-set)
2689 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2690 * is called.
2691 *
2692 * Returns the nodes in @nodes that follow @node in document order,
2693 * @nodes if @node is NULL or an empty node-set if @nodes
2694 * doesn't contain @node
2695 */
2696xmlNodeSetPtr
2697xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2698 xmlXPathNodeSetSort(nodes);
2699 return(xmlXPathNodeTrailingSorted(nodes, node));
2700}
2701
2702/**
2703 * xmlXPathTrailingSorted:
2704 * @nodes1: a node-set, sorted by document order
2705 * @nodes2: a node-set, sorted by document order
2706 *
2707 * Implements the EXSLT - Sets trailing() function:
2708 * node-set set:trailing (node-set, node-set)
2709 *
2710 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2711 * in document order, @nodes1 if @nodes2 is NULL or empty or
2712 * an empty node-set if @nodes1 doesn't contain @nodes2
2713 */
2714xmlNodeSetPtr
2715xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2716 if (xmlXPathNodeSetIsEmpty(nodes2))
2717 return(nodes1);
2718 return(xmlXPathNodeTrailingSorted(nodes1,
2719 xmlXPathNodeSetItem(nodes2, 0)));
2720}
2721
2722/**
2723 * xmlXPathTrailing:
2724 * @nodes1: a node-set
2725 * @nodes2: a node-set
2726 *
2727 * Implements the EXSLT - Sets trailing() function:
2728 * node-set set:trailing (node-set, node-set)
2729 * @nodes1 and @nodes2 are sorted by document order, then
2730 * #xmlXPathTrailingSorted is called.
2731 *
2732 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2733 * in document order, @nodes1 if @nodes2 is NULL or empty or
2734 * an empty node-set if @nodes1 doesn't contain @nodes2
2735 */
2736xmlNodeSetPtr
2737xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2738 if (xmlXPathNodeSetIsEmpty(nodes2))
2739 return(nodes1);
2740 if (xmlXPathNodeSetIsEmpty(nodes1))
2741 return(xmlXPathNodeSetCreate(NULL));
2742 xmlXPathNodeSetSort(nodes1);
2743 xmlXPathNodeSetSort(nodes2);
2744 return(xmlXPathNodeTrailingSorted(nodes1,
2745 xmlXPathNodeSetItem(nodes2, 0)));
2746}
2747
Owen Taylor3473f882001-02-23 17:55:21 +00002748/************************************************************************
2749 * *
2750 * Routines to handle extra functions *
2751 * *
2752 ************************************************************************/
2753
2754/**
2755 * xmlXPathRegisterFunc:
2756 * @ctxt: the XPath context
2757 * @name: the function name
2758 * @f: the function implementation or NULL
2759 *
2760 * Register a new function. If @f is NULL it unregisters the function
2761 *
2762 * Returns 0 in case of success, -1 in case of error
2763 */
2764int
2765xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2766 xmlXPathFunction f) {
2767 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2768}
2769
2770/**
2771 * xmlXPathRegisterFuncNS:
2772 * @ctxt: the XPath context
2773 * @name: the function name
2774 * @ns_uri: the function namespace URI
2775 * @f: the function implementation or NULL
2776 *
2777 * Register a new function. If @f is NULL it unregisters the function
2778 *
2779 * Returns 0 in case of success, -1 in case of error
2780 */
2781int
2782xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2783 const xmlChar *ns_uri, xmlXPathFunction f) {
2784 if (ctxt == NULL)
2785 return(-1);
2786 if (name == NULL)
2787 return(-1);
2788
2789 if (ctxt->funcHash == NULL)
2790 ctxt->funcHash = xmlHashCreate(0);
2791 if (ctxt->funcHash == NULL)
2792 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002793 if (f == NULL)
2794 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
Owen Taylor3473f882001-02-23 17:55:21 +00002795 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2796}
2797
2798/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002799 * xmlXPathRegisterFuncLookup:
2800 * @ctxt: the XPath context
2801 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002802 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002803 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002804 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002805 */
2806void
2807xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2808 xmlXPathFuncLookupFunc f,
2809 void *funcCtxt) {
2810 if (ctxt == NULL)
2811 return;
2812 ctxt->funcLookupFunc = (void *) f;
2813 ctxt->funcLookupData = funcCtxt;
2814}
2815
2816/**
Owen Taylor3473f882001-02-23 17:55:21 +00002817 * xmlXPathFunctionLookup:
2818 * @ctxt: the XPath context
2819 * @name: the function name
2820 *
2821 * Search in the Function array of the context for the given
2822 * function.
2823 *
2824 * Returns the xmlXPathFunction or NULL if not found
2825 */
2826xmlXPathFunction
2827xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002828 if (ctxt == NULL)
2829 return (NULL);
2830
2831 if (ctxt->funcLookupFunc != NULL) {
2832 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002833 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002834
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002835 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002836 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002837 if (ret != NULL)
2838 return(ret);
2839 }
Owen Taylor3473f882001-02-23 17:55:21 +00002840 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2841}
2842
2843/**
2844 * xmlXPathFunctionLookupNS:
2845 * @ctxt: the XPath context
2846 * @name: the function name
2847 * @ns_uri: the function namespace URI
2848 *
2849 * Search in the Function array of the context for the given
2850 * function.
2851 *
2852 * Returns the xmlXPathFunction or NULL if not found
2853 */
2854xmlXPathFunction
2855xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2856 const xmlChar *ns_uri) {
2857 if (ctxt == NULL)
2858 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002859 if (name == NULL)
2860 return(NULL);
2861
Thomas Broyerba4ad322001-07-26 16:55:21 +00002862 if (ctxt->funcLookupFunc != NULL) {
2863 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002864 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002865
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002866 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002867 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002868 if (ret != NULL)
2869 return(ret);
2870 }
2871
2872 if (ctxt->funcHash == NULL)
2873 return(NULL);
2874
Owen Taylor3473f882001-02-23 17:55:21 +00002875 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2876}
2877
2878/**
2879 * xmlXPathRegisteredFuncsCleanup:
2880 * @ctxt: the XPath context
2881 *
2882 * Cleanup the XPath context data associated to registered functions
2883 */
2884void
2885xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2886 if (ctxt == NULL)
2887 return;
2888
2889 xmlHashFree(ctxt->funcHash, NULL);
2890 ctxt->funcHash = NULL;
2891}
2892
2893/************************************************************************
2894 * *
William M. Brack08171912003-12-29 02:52:11 +00002895 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00002896 * *
2897 ************************************************************************/
2898
2899/**
2900 * xmlXPathRegisterVariable:
2901 * @ctxt: the XPath context
2902 * @name: the variable name
2903 * @value: the variable value or NULL
2904 *
2905 * Register a new variable value. If @value is NULL it unregisters
2906 * the variable
2907 *
2908 * Returns 0 in case of success, -1 in case of error
2909 */
2910int
2911xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2912 xmlXPathObjectPtr value) {
2913 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2914}
2915
2916/**
2917 * xmlXPathRegisterVariableNS:
2918 * @ctxt: the XPath context
2919 * @name: the variable name
2920 * @ns_uri: the variable namespace URI
2921 * @value: the variable value or NULL
2922 *
2923 * Register a new variable value. If @value is NULL it unregisters
2924 * the variable
2925 *
2926 * Returns 0 in case of success, -1 in case of error
2927 */
2928int
2929xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2930 const xmlChar *ns_uri,
2931 xmlXPathObjectPtr value) {
2932 if (ctxt == NULL)
2933 return(-1);
2934 if (name == NULL)
2935 return(-1);
2936
2937 if (ctxt->varHash == NULL)
2938 ctxt->varHash = xmlHashCreate(0);
2939 if (ctxt->varHash == NULL)
2940 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002941 if (value == NULL)
2942 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2943 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002944 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2945 (void *) value,
2946 (xmlHashDeallocator)xmlXPathFreeObject));
2947}
2948
2949/**
2950 * xmlXPathRegisterVariableLookup:
2951 * @ctxt: the XPath context
2952 * @f: the lookup function
2953 * @data: the lookup data
2954 *
2955 * register an external mechanism to do variable lookup
2956 */
2957void
2958xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2959 xmlXPathVariableLookupFunc f, void *data) {
2960 if (ctxt == NULL)
2961 return;
2962 ctxt->varLookupFunc = (void *) f;
2963 ctxt->varLookupData = data;
2964}
2965
2966/**
2967 * xmlXPathVariableLookup:
2968 * @ctxt: the XPath context
2969 * @name: the variable name
2970 *
2971 * Search in the Variable array of the context for the given
2972 * variable value.
2973 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002974 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002975 */
2976xmlXPathObjectPtr
2977xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2978 if (ctxt == NULL)
2979 return(NULL);
2980
2981 if (ctxt->varLookupFunc != NULL) {
2982 xmlXPathObjectPtr ret;
2983
2984 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2985 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002986 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002987 }
2988 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2989}
2990
2991/**
2992 * xmlXPathVariableLookupNS:
2993 * @ctxt: the XPath context
2994 * @name: the variable name
2995 * @ns_uri: the variable namespace URI
2996 *
2997 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002998 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002999 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003000 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003001 */
3002xmlXPathObjectPtr
3003xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3004 const xmlChar *ns_uri) {
3005 if (ctxt == NULL)
3006 return(NULL);
3007
3008 if (ctxt->varLookupFunc != NULL) {
3009 xmlXPathObjectPtr ret;
3010
3011 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3012 (ctxt->varLookupData, name, ns_uri);
3013 if (ret != NULL) return(ret);
3014 }
3015
3016 if (ctxt->varHash == NULL)
3017 return(NULL);
3018 if (name == NULL)
3019 return(NULL);
3020
Daniel Veillard8c357d52001-07-03 23:43:33 +00003021 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3022 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00003023}
3024
3025/**
3026 * xmlXPathRegisteredVariablesCleanup:
3027 * @ctxt: the XPath context
3028 *
3029 * Cleanup the XPath context data associated to registered variables
3030 */
3031void
3032xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3033 if (ctxt == NULL)
3034 return;
3035
Daniel Veillard76d66f42001-05-16 21:05:17 +00003036 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00003037 ctxt->varHash = NULL;
3038}
3039
3040/**
3041 * xmlXPathRegisterNs:
3042 * @ctxt: the XPath context
3043 * @prefix: the namespace prefix
3044 * @ns_uri: the namespace name
3045 *
3046 * Register a new namespace. If @ns_uri is NULL it unregisters
3047 * the namespace
3048 *
3049 * Returns 0 in case of success, -1 in case of error
3050 */
3051int
3052xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3053 const xmlChar *ns_uri) {
3054 if (ctxt == NULL)
3055 return(-1);
3056 if (prefix == NULL)
3057 return(-1);
3058
3059 if (ctxt->nsHash == NULL)
3060 ctxt->nsHash = xmlHashCreate(10);
3061 if (ctxt->nsHash == NULL)
3062 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003063 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003064 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003065 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003066 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003067 (xmlHashDeallocator)xmlFree));
3068}
3069
3070/**
3071 * xmlXPathNsLookup:
3072 * @ctxt: the XPath context
3073 * @prefix: the namespace prefix value
3074 *
3075 * Search in the namespace declaration array of the context for the given
3076 * namespace name associated to the given prefix
3077 *
3078 * Returns the value or NULL if not found
3079 */
3080const xmlChar *
3081xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3082 if (ctxt == NULL)
3083 return(NULL);
3084 if (prefix == NULL)
3085 return(NULL);
3086
3087#ifdef XML_XML_NAMESPACE
3088 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3089 return(XML_XML_NAMESPACE);
3090#endif
3091
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003092 if (ctxt->namespaces != NULL) {
3093 int i;
3094
3095 for (i = 0;i < ctxt->nsNr;i++) {
3096 if ((ctxt->namespaces[i] != NULL) &&
3097 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3098 return(ctxt->namespaces[i]->href);
3099 }
3100 }
Owen Taylor3473f882001-02-23 17:55:21 +00003101
3102 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3103}
3104
3105/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003106 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003107 * @ctxt: the XPath context
3108 *
3109 * Cleanup the XPath context data associated to registered variables
3110 */
3111void
3112xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3113 if (ctxt == NULL)
3114 return;
3115
Daniel Veillard42766c02002-08-22 20:52:17 +00003116 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003117 ctxt->nsHash = NULL;
3118}
3119
3120/************************************************************************
3121 * *
3122 * Routines to handle Values *
3123 * *
3124 ************************************************************************/
3125
William M. Brack08171912003-12-29 02:52:11 +00003126/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003127
3128/**
3129 * xmlXPathNewFloat:
3130 * @val: the double value
3131 *
3132 * Create a new xmlXPathObjectPtr of type double and of value @val
3133 *
3134 * Returns the newly created object.
3135 */
3136xmlXPathObjectPtr
3137xmlXPathNewFloat(double val) {
3138 xmlXPathObjectPtr ret;
3139
3140 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3141 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003142 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003143 return(NULL);
3144 }
3145 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3146 ret->type = XPATH_NUMBER;
3147 ret->floatval = val;
3148 return(ret);
3149}
3150
3151/**
3152 * xmlXPathNewBoolean:
3153 * @val: the boolean value
3154 *
3155 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3156 *
3157 * Returns the newly created object.
3158 */
3159xmlXPathObjectPtr
3160xmlXPathNewBoolean(int val) {
3161 xmlXPathObjectPtr ret;
3162
3163 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3164 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003165 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003166 return(NULL);
3167 }
3168 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3169 ret->type = XPATH_BOOLEAN;
3170 ret->boolval = (val != 0);
3171 return(ret);
3172}
3173
3174/**
3175 * xmlXPathNewString:
3176 * @val: the xmlChar * value
3177 *
3178 * Create a new xmlXPathObjectPtr of type string and of value @val
3179 *
3180 * Returns the newly created object.
3181 */
3182xmlXPathObjectPtr
3183xmlXPathNewString(const xmlChar *val) {
3184 xmlXPathObjectPtr ret;
3185
3186 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3187 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003188 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003189 return(NULL);
3190 }
3191 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3192 ret->type = XPATH_STRING;
3193 if (val != NULL)
3194 ret->stringval = xmlStrdup(val);
3195 else
3196 ret->stringval = xmlStrdup((const xmlChar *)"");
3197 return(ret);
3198}
3199
3200/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003201 * xmlXPathWrapString:
3202 * @val: the xmlChar * value
3203 *
3204 * Wraps the @val string into an XPath object.
3205 *
3206 * Returns the newly created object.
3207 */
3208xmlXPathObjectPtr
3209xmlXPathWrapString (xmlChar *val) {
3210 xmlXPathObjectPtr ret;
3211
3212 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3213 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003214 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003215 return(NULL);
3216 }
3217 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3218 ret->type = XPATH_STRING;
3219 ret->stringval = val;
3220 return(ret);
3221}
3222
3223/**
Owen Taylor3473f882001-02-23 17:55:21 +00003224 * xmlXPathNewCString:
3225 * @val: the char * value
3226 *
3227 * Create a new xmlXPathObjectPtr of type string and of value @val
3228 *
3229 * Returns the newly created object.
3230 */
3231xmlXPathObjectPtr
3232xmlXPathNewCString(const char *val) {
3233 xmlXPathObjectPtr ret;
3234
3235 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3236 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003237 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003238 return(NULL);
3239 }
3240 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3241 ret->type = XPATH_STRING;
3242 ret->stringval = xmlStrdup(BAD_CAST val);
3243 return(ret);
3244}
3245
3246/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003247 * xmlXPathWrapCString:
3248 * @val: the char * value
3249 *
3250 * Wraps a string into an XPath object.
3251 *
3252 * Returns the newly created object.
3253 */
3254xmlXPathObjectPtr
3255xmlXPathWrapCString (char * val) {
3256 return(xmlXPathWrapString((xmlChar *)(val)));
3257}
3258
3259/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003260 * xmlXPathWrapExternal:
3261 * @val: the user data
3262 *
3263 * Wraps the @val data into an XPath object.
3264 *
3265 * Returns the newly created object.
3266 */
3267xmlXPathObjectPtr
3268xmlXPathWrapExternal (void *val) {
3269 xmlXPathObjectPtr ret;
3270
3271 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3272 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003273 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003274 return(NULL);
3275 }
3276 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3277 ret->type = XPATH_USERS;
3278 ret->user = val;
3279 return(ret);
3280}
3281
3282/**
Owen Taylor3473f882001-02-23 17:55:21 +00003283 * xmlXPathObjectCopy:
3284 * @val: the original object
3285 *
3286 * allocate a new copy of a given object
3287 *
3288 * Returns the newly created object.
3289 */
3290xmlXPathObjectPtr
3291xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3292 xmlXPathObjectPtr ret;
3293
3294 if (val == NULL)
3295 return(NULL);
3296
3297 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3298 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003299 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003300 return(NULL);
3301 }
3302 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3303 switch (val->type) {
3304 case XPATH_BOOLEAN:
3305 case XPATH_NUMBER:
3306 case XPATH_POINT:
3307 case XPATH_RANGE:
3308 break;
3309 case XPATH_STRING:
3310 ret->stringval = xmlStrdup(val->stringval);
3311 break;
3312 case XPATH_XSLT_TREE:
3313 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003314 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003315 xmlNodePtr cur, tmp;
3316 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003317
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003318 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003319 top = xmlNewDoc(NULL);
3320 top->name = (char *)
3321 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003322 ret->user = top;
3323 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003324 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003325 cur = val->nodesetval->nodeTab[0]->children;
3326 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003327 tmp = xmlDocCopyNode(cur, top, 1);
3328 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003329 cur = cur->next;
3330 }
3331 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003332 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003333 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003334 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003335 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003336 break;
3337 case XPATH_NODESET:
3338 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003339 /* Do not deallocate the copied tree value */
3340 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003341 break;
3342 case XPATH_LOCATIONSET:
3343#ifdef LIBXML_XPTR_ENABLED
3344 {
3345 xmlLocationSetPtr loc = val->user;
3346 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3347 break;
3348 }
3349#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003350 case XPATH_USERS:
3351 ret->user = val->user;
3352 break;
3353 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003354 xmlGenericError(xmlGenericErrorContext,
3355 "xmlXPathObjectCopy: unsupported type %d\n",
3356 val->type);
3357 break;
3358 }
3359 return(ret);
3360}
3361
3362/**
3363 * xmlXPathFreeObject:
3364 * @obj: the object to free
3365 *
3366 * Free up an xmlXPathObjectPtr object.
3367 */
3368void
3369xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3370 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003371 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003372 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003373 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003374 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003375 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003376 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003377 xmlXPathFreeValueTree(obj->nodesetval);
3378 } else {
3379 if (obj->nodesetval != NULL)
3380 xmlXPathFreeNodeSet(obj->nodesetval);
3381 }
Owen Taylor3473f882001-02-23 17:55:21 +00003382#ifdef LIBXML_XPTR_ENABLED
3383 } else if (obj->type == XPATH_LOCATIONSET) {
3384 if (obj->user != NULL)
3385 xmlXPtrFreeLocationSet(obj->user);
3386#endif
3387 } else if (obj->type == XPATH_STRING) {
3388 if (obj->stringval != NULL)
3389 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003390 }
3391
Owen Taylor3473f882001-02-23 17:55:21 +00003392 xmlFree(obj);
3393}
3394
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003395
3396/************************************************************************
3397 * *
3398 * Type Casting Routines *
3399 * *
3400 ************************************************************************/
3401
3402/**
3403 * xmlXPathCastBooleanToString:
3404 * @val: a boolean
3405 *
3406 * Converts a boolean to its string value.
3407 *
3408 * Returns a newly allocated string.
3409 */
3410xmlChar *
3411xmlXPathCastBooleanToString (int val) {
3412 xmlChar *ret;
3413 if (val)
3414 ret = xmlStrdup((const xmlChar *) "true");
3415 else
3416 ret = xmlStrdup((const xmlChar *) "false");
3417 return(ret);
3418}
3419
3420/**
3421 * xmlXPathCastNumberToString:
3422 * @val: a number
3423 *
3424 * Converts a number to its string value.
3425 *
3426 * Returns a newly allocated string.
3427 */
3428xmlChar *
3429xmlXPathCastNumberToString (double val) {
3430 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003431 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003432 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003433 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003434 break;
3435 case -1:
3436 ret = xmlStrdup((const xmlChar *) "-Infinity");
3437 break;
3438 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003439 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003440 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003441 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3442 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003443 } else {
3444 /* could be improved */
3445 char buf[100];
3446 xmlXPathFormatNumber(val, buf, 100);
3447 ret = xmlStrdup((const xmlChar *) buf);
3448 }
3449 }
3450 return(ret);
3451}
3452
3453/**
3454 * xmlXPathCastNodeToString:
3455 * @node: a node
3456 *
3457 * Converts a node to its string value.
3458 *
3459 * Returns a newly allocated string.
3460 */
3461xmlChar *
3462xmlXPathCastNodeToString (xmlNodePtr node) {
3463 return(xmlNodeGetContent(node));
3464}
3465
3466/**
3467 * xmlXPathCastNodeSetToString:
3468 * @ns: a node-set
3469 *
3470 * Converts a node-set to its string value.
3471 *
3472 * Returns a newly allocated string.
3473 */
3474xmlChar *
3475xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3476 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3477 return(xmlStrdup((const xmlChar *) ""));
3478
3479 xmlXPathNodeSetSort(ns);
3480 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3481}
3482
3483/**
3484 * xmlXPathCastToString:
3485 * @val: an XPath object
3486 *
3487 * Converts an existing object to its string() equivalent
3488 *
3489 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003490 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003491 * string object).
3492 */
3493xmlChar *
3494xmlXPathCastToString(xmlXPathObjectPtr val) {
3495 xmlChar *ret = NULL;
3496
3497 if (val == NULL)
3498 return(xmlStrdup((const xmlChar *) ""));
3499 switch (val->type) {
3500 case XPATH_UNDEFINED:
3501#ifdef DEBUG_EXPR
3502 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3503#endif
3504 ret = xmlStrdup((const xmlChar *) "");
3505 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003506 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003507 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003508 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3509 break;
3510 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003511 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003512 case XPATH_BOOLEAN:
3513 ret = xmlXPathCastBooleanToString(val->boolval);
3514 break;
3515 case XPATH_NUMBER: {
3516 ret = xmlXPathCastNumberToString(val->floatval);
3517 break;
3518 }
3519 case XPATH_USERS:
3520 case XPATH_POINT:
3521 case XPATH_RANGE:
3522 case XPATH_LOCATIONSET:
3523 TODO
3524 ret = xmlStrdup((const xmlChar *) "");
3525 break;
3526 }
3527 return(ret);
3528}
3529
3530/**
3531 * xmlXPathConvertString:
3532 * @val: an XPath object
3533 *
3534 * Converts an existing object to its string() equivalent
3535 *
3536 * Returns the new object, the old one is freed (or the operation
3537 * is done directly on @val)
3538 */
3539xmlXPathObjectPtr
3540xmlXPathConvertString(xmlXPathObjectPtr val) {
3541 xmlChar *res = NULL;
3542
3543 if (val == NULL)
3544 return(xmlXPathNewCString(""));
3545
3546 switch (val->type) {
3547 case XPATH_UNDEFINED:
3548#ifdef DEBUG_EXPR
3549 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3550#endif
3551 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003552 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003553 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003554 res = xmlXPathCastNodeSetToString(val->nodesetval);
3555 break;
3556 case XPATH_STRING:
3557 return(val);
3558 case XPATH_BOOLEAN:
3559 res = xmlXPathCastBooleanToString(val->boolval);
3560 break;
3561 case XPATH_NUMBER:
3562 res = xmlXPathCastNumberToString(val->floatval);
3563 break;
3564 case XPATH_USERS:
3565 case XPATH_POINT:
3566 case XPATH_RANGE:
3567 case XPATH_LOCATIONSET:
3568 TODO;
3569 break;
3570 }
3571 xmlXPathFreeObject(val);
3572 if (res == NULL)
3573 return(xmlXPathNewCString(""));
3574 return(xmlXPathWrapString(res));
3575}
3576
3577/**
3578 * xmlXPathCastBooleanToNumber:
3579 * @val: a boolean
3580 *
3581 * Converts a boolean to its number value
3582 *
3583 * Returns the number value
3584 */
3585double
3586xmlXPathCastBooleanToNumber(int val) {
3587 if (val)
3588 return(1.0);
3589 return(0.0);
3590}
3591
3592/**
3593 * xmlXPathCastStringToNumber:
3594 * @val: a string
3595 *
3596 * Converts a string to its number value
3597 *
3598 * Returns the number value
3599 */
3600double
3601xmlXPathCastStringToNumber(const xmlChar * val) {
3602 return(xmlXPathStringEvalNumber(val));
3603}
3604
3605/**
3606 * xmlXPathCastNodeToNumber:
3607 * @node: a node
3608 *
3609 * Converts a node to its number value
3610 *
3611 * Returns the number value
3612 */
3613double
3614xmlXPathCastNodeToNumber (xmlNodePtr node) {
3615 xmlChar *strval;
3616 double ret;
3617
3618 if (node == NULL)
3619 return(xmlXPathNAN);
3620 strval = xmlXPathCastNodeToString(node);
3621 if (strval == NULL)
3622 return(xmlXPathNAN);
3623 ret = xmlXPathCastStringToNumber(strval);
3624 xmlFree(strval);
3625
3626 return(ret);
3627}
3628
3629/**
3630 * xmlXPathCastNodeSetToNumber:
3631 * @ns: a node-set
3632 *
3633 * Converts a node-set to its number value
3634 *
3635 * Returns the number value
3636 */
3637double
3638xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3639 xmlChar *str;
3640 double ret;
3641
3642 if (ns == NULL)
3643 return(xmlXPathNAN);
3644 str = xmlXPathCastNodeSetToString(ns);
3645 ret = xmlXPathCastStringToNumber(str);
3646 xmlFree(str);
3647 return(ret);
3648}
3649
3650/**
3651 * xmlXPathCastToNumber:
3652 * @val: an XPath object
3653 *
3654 * Converts an XPath object to its number value
3655 *
3656 * Returns the number value
3657 */
3658double
3659xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3660 double ret = 0.0;
3661
3662 if (val == NULL)
3663 return(xmlXPathNAN);
3664 switch (val->type) {
3665 case XPATH_UNDEFINED:
3666#ifdef DEGUB_EXPR
3667 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3668#endif
3669 ret = xmlXPathNAN;
3670 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003671 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003672 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003673 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3674 break;
3675 case XPATH_STRING:
3676 ret = xmlXPathCastStringToNumber(val->stringval);
3677 break;
3678 case XPATH_NUMBER:
3679 ret = val->floatval;
3680 break;
3681 case XPATH_BOOLEAN:
3682 ret = xmlXPathCastBooleanToNumber(val->boolval);
3683 break;
3684 case XPATH_USERS:
3685 case XPATH_POINT:
3686 case XPATH_RANGE:
3687 case XPATH_LOCATIONSET:
3688 TODO;
3689 ret = xmlXPathNAN;
3690 break;
3691 }
3692 return(ret);
3693}
3694
3695/**
3696 * xmlXPathConvertNumber:
3697 * @val: an XPath object
3698 *
3699 * Converts an existing object to its number() equivalent
3700 *
3701 * Returns the new object, the old one is freed (or the operation
3702 * is done directly on @val)
3703 */
3704xmlXPathObjectPtr
3705xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3706 xmlXPathObjectPtr ret;
3707
3708 if (val == NULL)
3709 return(xmlXPathNewFloat(0.0));
3710 if (val->type == XPATH_NUMBER)
3711 return(val);
3712 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3713 xmlXPathFreeObject(val);
3714 return(ret);
3715}
3716
3717/**
3718 * xmlXPathCastNumberToBoolean:
3719 * @val: a number
3720 *
3721 * Converts a number to its boolean value
3722 *
3723 * Returns the boolean value
3724 */
3725int
3726xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003727 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003728 return(0);
3729 return(1);
3730}
3731
3732/**
3733 * xmlXPathCastStringToBoolean:
3734 * @val: a string
3735 *
3736 * Converts a string to its boolean value
3737 *
3738 * Returns the boolean value
3739 */
3740int
3741xmlXPathCastStringToBoolean (const xmlChar *val) {
3742 if ((val == NULL) || (xmlStrlen(val) == 0))
3743 return(0);
3744 return(1);
3745}
3746
3747/**
3748 * xmlXPathCastNodeSetToBoolean:
3749 * @ns: a node-set
3750 *
3751 * Converts a node-set to its boolean value
3752 *
3753 * Returns the boolean value
3754 */
3755int
3756xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3757 if ((ns == NULL) || (ns->nodeNr == 0))
3758 return(0);
3759 return(1);
3760}
3761
3762/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003763 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003764 * @val: an XPath object
3765 *
3766 * Converts an XPath object to its boolean value
3767 *
3768 * Returns the boolean value
3769 */
3770int
3771xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3772 int ret = 0;
3773
3774 if (val == NULL)
3775 return(0);
3776 switch (val->type) {
3777 case XPATH_UNDEFINED:
3778#ifdef DEBUG_EXPR
3779 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3780#endif
3781 ret = 0;
3782 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003783 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003784 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003785 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3786 break;
3787 case XPATH_STRING:
3788 ret = xmlXPathCastStringToBoolean(val->stringval);
3789 break;
3790 case XPATH_NUMBER:
3791 ret = xmlXPathCastNumberToBoolean(val->floatval);
3792 break;
3793 case XPATH_BOOLEAN:
3794 ret = val->boolval;
3795 break;
3796 case XPATH_USERS:
3797 case XPATH_POINT:
3798 case XPATH_RANGE:
3799 case XPATH_LOCATIONSET:
3800 TODO;
3801 ret = 0;
3802 break;
3803 }
3804 return(ret);
3805}
3806
3807
3808/**
3809 * xmlXPathConvertBoolean:
3810 * @val: an XPath object
3811 *
3812 * Converts an existing object to its boolean() equivalent
3813 *
3814 * Returns the new object, the old one is freed (or the operation
3815 * is done directly on @val)
3816 */
3817xmlXPathObjectPtr
3818xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3819 xmlXPathObjectPtr ret;
3820
3821 if (val == NULL)
3822 return(xmlXPathNewBoolean(0));
3823 if (val->type == XPATH_BOOLEAN)
3824 return(val);
3825 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3826 xmlXPathFreeObject(val);
3827 return(ret);
3828}
3829
Owen Taylor3473f882001-02-23 17:55:21 +00003830/************************************************************************
3831 * *
3832 * Routines to handle XPath contexts *
3833 * *
3834 ************************************************************************/
3835
3836/**
3837 * xmlXPathNewContext:
3838 * @doc: the XML document
3839 *
3840 * Create a new xmlXPathContext
3841 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003842 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003843 */
3844xmlXPathContextPtr
3845xmlXPathNewContext(xmlDocPtr doc) {
3846 xmlXPathContextPtr ret;
3847
3848 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3849 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003850 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003851 return(NULL);
3852 }
3853 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3854 ret->doc = doc;
3855 ret->node = NULL;
3856
3857 ret->varHash = NULL;
3858
3859 ret->nb_types = 0;
3860 ret->max_types = 0;
3861 ret->types = NULL;
3862
3863 ret->funcHash = xmlHashCreate(0);
3864
3865 ret->nb_axis = 0;
3866 ret->max_axis = 0;
3867 ret->axis = NULL;
3868
3869 ret->nsHash = NULL;
3870 ret->user = NULL;
3871
3872 ret->contextSize = -1;
3873 ret->proximityPosition = -1;
3874
3875 xmlXPathRegisterAllFunctions(ret);
3876
3877 return(ret);
3878}
3879
3880/**
3881 * xmlXPathFreeContext:
3882 * @ctxt: the context to free
3883 *
3884 * Free up an xmlXPathContext
3885 */
3886void
3887xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3888 xmlXPathRegisteredNsCleanup(ctxt);
3889 xmlXPathRegisteredFuncsCleanup(ctxt);
3890 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003891 xmlFree(ctxt);
3892}
3893
3894/************************************************************************
3895 * *
3896 * Routines to handle XPath parser contexts *
3897 * *
3898 ************************************************************************/
3899
3900#define CHECK_CTXT(ctxt) \
3901 if (ctxt == NULL) { \
3902 xmlGenericError(xmlGenericErrorContext, \
3903 "%s:%d Internal error: ctxt == NULL\n", \
3904 __FILE__, __LINE__); \
3905 } \
3906
3907
3908#define CHECK_CONTEXT(ctxt) \
3909 if (ctxt == NULL) { \
3910 xmlGenericError(xmlGenericErrorContext, \
3911 "%s:%d Internal error: no context\n", \
3912 __FILE__, __LINE__); \
3913 } \
3914 else if (ctxt->doc == NULL) { \
3915 xmlGenericError(xmlGenericErrorContext, \
3916 "%s:%d Internal error: no document\n", \
3917 __FILE__, __LINE__); \
3918 } \
3919 else if (ctxt->doc->children == NULL) { \
3920 xmlGenericError(xmlGenericErrorContext, \
3921 "%s:%d Internal error: document without root\n", \
3922 __FILE__, __LINE__); \
3923 } \
3924
3925
3926/**
3927 * xmlXPathNewParserContext:
3928 * @str: the XPath expression
3929 * @ctxt: the XPath context
3930 *
3931 * Create a new xmlXPathParserContext
3932 *
3933 * Returns the xmlXPathParserContext just allocated.
3934 */
3935xmlXPathParserContextPtr
3936xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3937 xmlXPathParserContextPtr ret;
3938
3939 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3940 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003941 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003942 return(NULL);
3943 }
3944 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3945 ret->cur = ret->base = str;
3946 ret->context = ctxt;
3947
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003948 ret->comp = xmlXPathNewCompExpr();
3949 if (ret->comp == NULL) {
3950 xmlFree(ret->valueTab);
3951 xmlFree(ret);
3952 return(NULL);
3953 }
Daniel Veillard4773df22004-01-23 13:15:13 +00003954 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
3955 ret->comp->dict = ctxt->dict;
3956 xmlDictReference(ret->comp->dict);
3957 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003958
3959 return(ret);
3960}
3961
3962/**
3963 * xmlXPathCompParserContext:
3964 * @comp: the XPath compiled expression
3965 * @ctxt: the XPath context
3966 *
3967 * Create a new xmlXPathParserContext when processing a compiled expression
3968 *
3969 * Returns the xmlXPathParserContext just allocated.
3970 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003971static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003972xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3973 xmlXPathParserContextPtr ret;
3974
3975 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3976 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003977 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003978 return(NULL);
3979 }
3980 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3981
Owen Taylor3473f882001-02-23 17:55:21 +00003982 /* Allocate the value stack */
3983 ret->valueTab = (xmlXPathObjectPtr *)
3984 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003985 if (ret->valueTab == NULL) {
3986 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003987 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003988 return(NULL);
3989 }
Owen Taylor3473f882001-02-23 17:55:21 +00003990 ret->valueNr = 0;
3991 ret->valueMax = 10;
3992 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003993
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003994 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003995 ret->comp = comp;
3996
Owen Taylor3473f882001-02-23 17:55:21 +00003997 return(ret);
3998}
3999
4000/**
4001 * xmlXPathFreeParserContext:
4002 * @ctxt: the context to free
4003 *
4004 * Free up an xmlXPathParserContext
4005 */
4006void
4007xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
4008 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004009 xmlFree(ctxt->valueTab);
4010 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004011 if (ctxt->comp)
4012 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00004013 xmlFree(ctxt);
4014}
4015
4016/************************************************************************
4017 * *
4018 * The implicit core function library *
4019 * *
4020 ************************************************************************/
4021
Owen Taylor3473f882001-02-23 17:55:21 +00004022/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004023 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00004024 * @node: a node pointer
4025 *
4026 * Function computing the beginning of the string value of the node,
4027 * used to speed up comparisons
4028 *
4029 * Returns an int usable as a hash
4030 */
4031static unsigned int
4032xmlXPathNodeValHash(xmlNodePtr node) {
4033 int len = 2;
4034 const xmlChar * string = NULL;
4035 xmlNodePtr tmp = NULL;
4036 unsigned int ret = 0;
4037
4038 if (node == NULL)
4039 return(0);
4040
Daniel Veillard9adc0462003-03-24 18:39:54 +00004041 if (node->type == XML_DOCUMENT_NODE) {
4042 tmp = xmlDocGetRootElement((xmlDocPtr) node);
4043 if (tmp == NULL)
4044 node = node->children;
4045 else
4046 node = tmp;
4047
4048 if (node == NULL)
4049 return(0);
4050 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004051
4052 switch (node->type) {
4053 case XML_COMMENT_NODE:
4054 case XML_PI_NODE:
4055 case XML_CDATA_SECTION_NODE:
4056 case XML_TEXT_NODE:
4057 string = node->content;
4058 if (string == NULL)
4059 return(0);
4060 if (string[0] == 0)
4061 return(0);
4062 return(((unsigned int) string[0]) +
4063 (((unsigned int) string[1]) << 8));
4064 case XML_NAMESPACE_DECL:
4065 string = ((xmlNsPtr)node)->href;
4066 if (string == NULL)
4067 return(0);
4068 if (string[0] == 0)
4069 return(0);
4070 return(((unsigned int) string[0]) +
4071 (((unsigned int) string[1]) << 8));
4072 case XML_ATTRIBUTE_NODE:
4073 tmp = ((xmlAttrPtr) node)->children;
4074 break;
4075 case XML_ELEMENT_NODE:
4076 tmp = node->children;
4077 break;
4078 default:
4079 return(0);
4080 }
4081 while (tmp != NULL) {
4082 switch (tmp->type) {
4083 case XML_COMMENT_NODE:
4084 case XML_PI_NODE:
4085 case XML_CDATA_SECTION_NODE:
4086 case XML_TEXT_NODE:
4087 string = tmp->content;
4088 break;
4089 case XML_NAMESPACE_DECL:
4090 string = ((xmlNsPtr)tmp)->href;
4091 break;
4092 default:
4093 break;
4094 }
4095 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004096 if (len == 1) {
4097 return(ret + (((unsigned int) string[0]) << 8));
4098 }
4099 if (string[1] == 0) {
4100 len = 1;
4101 ret = (unsigned int) string[0];
4102 } else {
4103 return(((unsigned int) string[0]) +
4104 (((unsigned int) string[1]) << 8));
4105 }
4106 }
4107 /*
4108 * Skip to next node
4109 */
4110 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4111 if (tmp->children->type != XML_ENTITY_DECL) {
4112 tmp = tmp->children;
4113 continue;
4114 }
4115 }
4116 if (tmp == node)
4117 break;
4118
4119 if (tmp->next != NULL) {
4120 tmp = tmp->next;
4121 continue;
4122 }
4123
4124 do {
4125 tmp = tmp->parent;
4126 if (tmp == NULL)
4127 break;
4128 if (tmp == node) {
4129 tmp = NULL;
4130 break;
4131 }
4132 if (tmp->next != NULL) {
4133 tmp = tmp->next;
4134 break;
4135 }
4136 } while (tmp != NULL);
4137 }
4138 return(ret);
4139}
4140
4141/**
4142 * xmlXPathStringHash:
4143 * @string: a string
4144 *
4145 * Function computing the beginning of the string value of the node,
4146 * used to speed up comparisons
4147 *
4148 * Returns an int usable as a hash
4149 */
4150static unsigned int
4151xmlXPathStringHash(const xmlChar * string) {
4152 if (string == NULL)
4153 return((unsigned int) 0);
4154 if (string[0] == 0)
4155 return(0);
4156 return(((unsigned int) string[0]) +
4157 (((unsigned int) string[1]) << 8));
4158}
4159
4160/**
Owen Taylor3473f882001-02-23 17:55:21 +00004161 * xmlXPathCompareNodeSetFloat:
4162 * @ctxt: the XPath Parser context
4163 * @inf: less than (1) or greater than (0)
4164 * @strict: is the comparison strict
4165 * @arg: the node set
4166 * @f: the value
4167 *
4168 * Implement the compare operation between a nodeset and a number
4169 * @ns < @val (1, 1, ...
4170 * @ns <= @val (1, 0, ...
4171 * @ns > @val (0, 1, ...
4172 * @ns >= @val (0, 0, ...
4173 *
4174 * If one object to be compared is a node-set and the other is a number,
4175 * then the comparison will be true if and only if there is a node in the
4176 * node-set such that the result of performing the comparison on the number
4177 * to be compared and on the result of converting the string-value of that
4178 * node to a number using the number function is true.
4179 *
4180 * Returns 0 or 1 depending on the results of the test.
4181 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004182static int
Owen Taylor3473f882001-02-23 17:55:21 +00004183xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4184 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4185 int i, ret = 0;
4186 xmlNodeSetPtr ns;
4187 xmlChar *str2;
4188
4189 if ((f == NULL) || (arg == NULL) ||
4190 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4191 xmlXPathFreeObject(arg);
4192 xmlXPathFreeObject(f);
4193 return(0);
4194 }
4195 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004196 if (ns != NULL) {
4197 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004198 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004199 if (str2 != NULL) {
4200 valuePush(ctxt,
4201 xmlXPathNewString(str2));
4202 xmlFree(str2);
4203 xmlXPathNumberFunction(ctxt, 1);
4204 valuePush(ctxt, xmlXPathObjectCopy(f));
4205 ret = xmlXPathCompareValues(ctxt, inf, strict);
4206 if (ret)
4207 break;
4208 }
4209 }
Owen Taylor3473f882001-02-23 17:55:21 +00004210 }
4211 xmlXPathFreeObject(arg);
4212 xmlXPathFreeObject(f);
4213 return(ret);
4214}
4215
4216/**
4217 * xmlXPathCompareNodeSetString:
4218 * @ctxt: the XPath Parser context
4219 * @inf: less than (1) or greater than (0)
4220 * @strict: is the comparison strict
4221 * @arg: the node set
4222 * @s: the value
4223 *
4224 * Implement the compare operation between a nodeset and a string
4225 * @ns < @val (1, 1, ...
4226 * @ns <= @val (1, 0, ...
4227 * @ns > @val (0, 1, ...
4228 * @ns >= @val (0, 0, ...
4229 *
4230 * If one object to be compared is a node-set and the other is a string,
4231 * then the comparison will be true if and only if there is a node in
4232 * the node-set such that the result of performing the comparison on the
4233 * string-value of the node and the other string is true.
4234 *
4235 * Returns 0 or 1 depending on the results of the test.
4236 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004237static int
Owen Taylor3473f882001-02-23 17:55:21 +00004238xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4239 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4240 int i, ret = 0;
4241 xmlNodeSetPtr ns;
4242 xmlChar *str2;
4243
4244 if ((s == NULL) || (arg == NULL) ||
4245 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4246 xmlXPathFreeObject(arg);
4247 xmlXPathFreeObject(s);
4248 return(0);
4249 }
4250 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004251 if (ns != NULL) {
4252 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004253 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004254 if (str2 != NULL) {
4255 valuePush(ctxt,
4256 xmlXPathNewString(str2));
4257 xmlFree(str2);
4258 valuePush(ctxt, xmlXPathObjectCopy(s));
4259 ret = xmlXPathCompareValues(ctxt, inf, strict);
4260 if (ret)
4261 break;
4262 }
4263 }
Owen Taylor3473f882001-02-23 17:55:21 +00004264 }
4265 xmlXPathFreeObject(arg);
4266 xmlXPathFreeObject(s);
4267 return(ret);
4268}
4269
4270/**
4271 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004272 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004273 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004274 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004275 * @arg2: the second node set object
4276 *
4277 * Implement the compare operation on nodesets:
4278 *
4279 * If both objects to be compared are node-sets, then the comparison
4280 * will be true if and only if there is a node in the first node-set
4281 * and a node in the second node-set such that the result of performing
4282 * the comparison on the string-values of the two nodes is true.
4283 * ....
4284 * When neither object to be compared is a node-set and the operator
4285 * is <=, <, >= or >, then the objects are compared by converting both
4286 * objects to numbers and comparing the numbers according to IEEE 754.
4287 * ....
4288 * The number function converts its argument to a number as follows:
4289 * - a string that consists of optional whitespace followed by an
4290 * optional minus sign followed by a Number followed by whitespace
4291 * is converted to the IEEE 754 number that is nearest (according
4292 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4293 * represented by the string; any other string is converted to NaN
4294 *
4295 * Conclusion all nodes need to be converted first to their string value
4296 * and then the comparison must be done when possible
4297 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004298static int
4299xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004300 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4301 int i, j, init = 0;
4302 double val1;
4303 double *values2;
4304 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004305 xmlNodeSetPtr ns1;
4306 xmlNodeSetPtr ns2;
4307
4308 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004309 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4310 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004311 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004312 }
Owen Taylor3473f882001-02-23 17:55:21 +00004313 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004314 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4315 xmlXPathFreeObject(arg1);
4316 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004317 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004318 }
Owen Taylor3473f882001-02-23 17:55:21 +00004319
4320 ns1 = arg1->nodesetval;
4321 ns2 = arg2->nodesetval;
4322
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004323 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004324 xmlXPathFreeObject(arg1);
4325 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004326 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004327 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004328 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004329 xmlXPathFreeObject(arg1);
4330 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004331 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004332 }
Owen Taylor3473f882001-02-23 17:55:21 +00004333
4334 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4335 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004336 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004337 xmlXPathFreeObject(arg1);
4338 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004339 return(0);
4340 }
4341 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004342 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004343 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004344 continue;
4345 for (j = 0;j < ns2->nodeNr;j++) {
4346 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004347 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004348 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004349 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004350 continue;
4351 if (inf && strict)
4352 ret = (val1 < values2[j]);
4353 else if (inf && !strict)
4354 ret = (val1 <= values2[j]);
4355 else if (!inf && strict)
4356 ret = (val1 > values2[j]);
4357 else if (!inf && !strict)
4358 ret = (val1 >= values2[j]);
4359 if (ret)
4360 break;
4361 }
4362 if (ret)
4363 break;
4364 init = 1;
4365 }
4366 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004367 xmlXPathFreeObject(arg1);
4368 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004369 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004370}
4371
4372/**
4373 * xmlXPathCompareNodeSetValue:
4374 * @ctxt: the XPath Parser context
4375 * @inf: less than (1) or greater than (0)
4376 * @strict: is the comparison strict
4377 * @arg: the node set
4378 * @val: the value
4379 *
4380 * Implement the compare operation between a nodeset and a value
4381 * @ns < @val (1, 1, ...
4382 * @ns <= @val (1, 0, ...
4383 * @ns > @val (0, 1, ...
4384 * @ns >= @val (0, 0, ...
4385 *
4386 * If one object to be compared is a node-set and the other is a boolean,
4387 * then the comparison will be true if and only if the result of performing
4388 * the comparison on the boolean and on the result of converting
4389 * the node-set to a boolean using the boolean function is true.
4390 *
4391 * Returns 0 or 1 depending on the results of the test.
4392 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004393static int
Owen Taylor3473f882001-02-23 17:55:21 +00004394xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4395 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4396 if ((val == NULL) || (arg == NULL) ||
4397 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4398 return(0);
4399
4400 switch(val->type) {
4401 case XPATH_NUMBER:
4402 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4403 case XPATH_NODESET:
4404 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004405 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004406 case XPATH_STRING:
4407 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4408 case XPATH_BOOLEAN:
4409 valuePush(ctxt, arg);
4410 xmlXPathBooleanFunction(ctxt, 1);
4411 valuePush(ctxt, val);
4412 return(xmlXPathCompareValues(ctxt, inf, strict));
4413 default:
4414 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004415 }
4416 return(0);
4417}
4418
4419/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004420 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004421 * @arg: the nodeset object argument
4422 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004423 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004424 *
4425 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4426 * If one object to be compared is a node-set and the other is a string,
4427 * then the comparison will be true if and only if there is a node in
4428 * the node-set such that the result of performing the comparison on the
4429 * string-value of the node and the other string is true.
4430 *
4431 * Returns 0 or 1 depending on the results of the test.
4432 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004433static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004434xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004435{
Owen Taylor3473f882001-02-23 17:55:21 +00004436 int i;
4437 xmlNodeSetPtr ns;
4438 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004439 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004440
4441 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004442 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4443 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004444 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004445 /*
4446 * A NULL nodeset compared with a string is always false
4447 * (since there is no node equal, and no node not equal)
4448 */
4449 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004450 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004451 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004452 for (i = 0; i < ns->nodeNr; i++) {
4453 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4454 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4455 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4456 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004457 if (neq)
4458 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004459 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004460 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4461 if (neq)
4462 continue;
4463 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004464 } else if (neq) {
4465 if (str2 != NULL)
4466 xmlFree(str2);
4467 return (1);
4468 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004469 if (str2 != NULL)
4470 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004471 } else if (neq)
4472 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004473 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004474 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004475}
4476
4477/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004478 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004479 * @arg: the nodeset object argument
4480 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004481 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004482 *
4483 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4484 * If one object to be compared is a node-set and the other is a number,
4485 * then the comparison will be true if and only if there is a node in
4486 * the node-set such that the result of performing the comparison on the
4487 * number to be compared and on the result of converting the string-value
4488 * of that node to a number using the number function is true.
4489 *
4490 * Returns 0 or 1 depending on the results of the test.
4491 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004492static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004493xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4494 xmlXPathObjectPtr arg, double f, int neq) {
4495 int i, ret=0;
4496 xmlNodeSetPtr ns;
4497 xmlChar *str2;
4498 xmlXPathObjectPtr val;
4499 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004500
4501 if ((arg == NULL) ||
4502 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4503 return(0);
4504
William M. Brack0c022ad2002-07-12 00:56:01 +00004505 ns = arg->nodesetval;
4506 if (ns != NULL) {
4507 for (i=0;i<ns->nodeNr;i++) {
4508 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4509 if (str2 != NULL) {
4510 valuePush(ctxt, xmlXPathNewString(str2));
4511 xmlFree(str2);
4512 xmlXPathNumberFunction(ctxt, 1);
4513 val = valuePop(ctxt);
4514 v = val->floatval;
4515 xmlXPathFreeObject(val);
4516 if (!xmlXPathIsNaN(v)) {
4517 if ((!neq) && (v==f)) {
4518 ret = 1;
4519 break;
4520 } else if ((neq) && (v!=f)) {
4521 ret = 1;
4522 break;
4523 }
4524 }
4525 }
4526 }
4527 }
4528
4529 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004530}
4531
4532
4533/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004534 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004535 * @arg1: first nodeset object argument
4536 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004537 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004538 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004539 * Implement the equal / not equal operation on XPath nodesets:
4540 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004541 * If both objects to be compared are node-sets, then the comparison
4542 * will be true if and only if there is a node in the first node-set and
4543 * a node in the second node-set such that the result of performing the
4544 * comparison on the string-values of the two nodes is true.
4545 *
4546 * (needless to say, this is a costly operation)
4547 *
4548 * Returns 0 or 1 depending on the results of the test.
4549 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004550static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004551xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004552 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004553 unsigned int *hashs1;
4554 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004555 xmlChar **values1;
4556 xmlChar **values2;
4557 int ret = 0;
4558 xmlNodeSetPtr ns1;
4559 xmlNodeSetPtr ns2;
4560
4561 if ((arg1 == NULL) ||
4562 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4563 return(0);
4564 if ((arg2 == NULL) ||
4565 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4566 return(0);
4567
4568 ns1 = arg1->nodesetval;
4569 ns2 = arg2->nodesetval;
4570
Daniel Veillard911f49a2001-04-07 15:39:35 +00004571 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004572 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004573 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004574 return(0);
4575
4576 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004577 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004578 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004579 if (neq == 0)
4580 for (i = 0;i < ns1->nodeNr;i++)
4581 for (j = 0;j < ns2->nodeNr;j++)
4582 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4583 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004584
4585 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004586 if (values1 == NULL) {
4587 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004588 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004589 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004590 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4591 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004592 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004593 xmlFree(values1);
4594 return(0);
4595 }
Owen Taylor3473f882001-02-23 17:55:21 +00004596 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4597 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4598 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004599 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004600 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004601 xmlFree(values1);
4602 return(0);
4603 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004604 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4605 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004606 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004607 xmlFree(hashs1);
4608 xmlFree(values1);
4609 xmlFree(values2);
4610 return(0);
4611 }
Owen Taylor3473f882001-02-23 17:55:21 +00004612 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4613 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004614 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004615 for (j = 0;j < ns2->nodeNr;j++) {
4616 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004617 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004618 if (hashs1[i] != hashs2[j]) {
4619 if (neq) {
4620 ret = 1;
4621 break;
4622 }
4623 }
4624 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004625 if (values1[i] == NULL)
4626 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4627 if (values2[j] == NULL)
4628 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004629 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004630 if (ret)
4631 break;
4632 }
Owen Taylor3473f882001-02-23 17:55:21 +00004633 }
4634 if (ret)
4635 break;
4636 }
4637 for (i = 0;i < ns1->nodeNr;i++)
4638 if (values1[i] != NULL)
4639 xmlFree(values1[i]);
4640 for (j = 0;j < ns2->nodeNr;j++)
4641 if (values2[j] != NULL)
4642 xmlFree(values2[j]);
4643 xmlFree(values1);
4644 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004645 xmlFree(hashs1);
4646 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004647 return(ret);
4648}
4649
William M. Brack0c022ad2002-07-12 00:56:01 +00004650static int
4651xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4652 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004653 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004654 /*
4655 *At this point we are assured neither arg1 nor arg2
4656 *is a nodeset, so we can just pick the appropriate routine.
4657 */
Owen Taylor3473f882001-02-23 17:55:21 +00004658 switch (arg1->type) {
4659 case XPATH_UNDEFINED:
4660#ifdef DEBUG_EXPR
4661 xmlGenericError(xmlGenericErrorContext,
4662 "Equal: undefined\n");
4663#endif
4664 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004665 case XPATH_BOOLEAN:
4666 switch (arg2->type) {
4667 case XPATH_UNDEFINED:
4668#ifdef DEBUG_EXPR
4669 xmlGenericError(xmlGenericErrorContext,
4670 "Equal: undefined\n");
4671#endif
4672 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004673 case XPATH_BOOLEAN:
4674#ifdef DEBUG_EXPR
4675 xmlGenericError(xmlGenericErrorContext,
4676 "Equal: %d boolean %d \n",
4677 arg1->boolval, arg2->boolval);
4678#endif
4679 ret = (arg1->boolval == arg2->boolval);
4680 break;
4681 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004682 ret = (arg1->boolval ==
4683 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004684 break;
4685 case XPATH_STRING:
4686 if ((arg2->stringval == NULL) ||
4687 (arg2->stringval[0] == 0)) ret = 0;
4688 else
4689 ret = 1;
4690 ret = (arg1->boolval == ret);
4691 break;
4692 case XPATH_USERS:
4693 case XPATH_POINT:
4694 case XPATH_RANGE:
4695 case XPATH_LOCATIONSET:
4696 TODO
4697 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004698 case XPATH_NODESET:
4699 case XPATH_XSLT_TREE:
4700 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004701 }
4702 break;
4703 case XPATH_NUMBER:
4704 switch (arg2->type) {
4705 case XPATH_UNDEFINED:
4706#ifdef DEBUG_EXPR
4707 xmlGenericError(xmlGenericErrorContext,
4708 "Equal: undefined\n");
4709#endif
4710 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004711 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004712 ret = (arg2->boolval==
4713 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004714 break;
4715 case XPATH_STRING:
4716 valuePush(ctxt, arg2);
4717 xmlXPathNumberFunction(ctxt, 1);
4718 arg2 = valuePop(ctxt);
4719 /* no break on purpose */
4720 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004721 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004722 if (xmlXPathIsNaN(arg1->floatval) ||
4723 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004724 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004725 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4726 if (xmlXPathIsInf(arg2->floatval) == 1)
4727 ret = 1;
4728 else
4729 ret = 0;
4730 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4731 if (xmlXPathIsInf(arg2->floatval) == -1)
4732 ret = 1;
4733 else
4734 ret = 0;
4735 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4736 if (xmlXPathIsInf(arg1->floatval) == 1)
4737 ret = 1;
4738 else
4739 ret = 0;
4740 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4741 if (xmlXPathIsInf(arg1->floatval) == -1)
4742 ret = 1;
4743 else
4744 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004745 } else {
4746 ret = (arg1->floatval == arg2->floatval);
4747 }
Owen Taylor3473f882001-02-23 17:55:21 +00004748 break;
4749 case XPATH_USERS:
4750 case XPATH_POINT:
4751 case XPATH_RANGE:
4752 case XPATH_LOCATIONSET:
4753 TODO
4754 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004755 case XPATH_NODESET:
4756 case XPATH_XSLT_TREE:
4757 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004758 }
4759 break;
4760 case XPATH_STRING:
4761 switch (arg2->type) {
4762 case XPATH_UNDEFINED:
4763#ifdef DEBUG_EXPR
4764 xmlGenericError(xmlGenericErrorContext,
4765 "Equal: undefined\n");
4766#endif
4767 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004768 case XPATH_BOOLEAN:
4769 if ((arg1->stringval == NULL) ||
4770 (arg1->stringval[0] == 0)) ret = 0;
4771 else
4772 ret = 1;
4773 ret = (arg2->boolval == ret);
4774 break;
4775 case XPATH_STRING:
4776 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4777 break;
4778 case XPATH_NUMBER:
4779 valuePush(ctxt, arg1);
4780 xmlXPathNumberFunction(ctxt, 1);
4781 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004782 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004783 if (xmlXPathIsNaN(arg1->floatval) ||
4784 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004785 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004786 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4787 if (xmlXPathIsInf(arg2->floatval) == 1)
4788 ret = 1;
4789 else
4790 ret = 0;
4791 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4792 if (xmlXPathIsInf(arg2->floatval) == -1)
4793 ret = 1;
4794 else
4795 ret = 0;
4796 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4797 if (xmlXPathIsInf(arg1->floatval) == 1)
4798 ret = 1;
4799 else
4800 ret = 0;
4801 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4802 if (xmlXPathIsInf(arg1->floatval) == -1)
4803 ret = 1;
4804 else
4805 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004806 } else {
4807 ret = (arg1->floatval == arg2->floatval);
4808 }
Owen Taylor3473f882001-02-23 17:55:21 +00004809 break;
4810 case XPATH_USERS:
4811 case XPATH_POINT:
4812 case XPATH_RANGE:
4813 case XPATH_LOCATIONSET:
4814 TODO
4815 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004816 case XPATH_NODESET:
4817 case XPATH_XSLT_TREE:
4818 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004819 }
4820 break;
4821 case XPATH_USERS:
4822 case XPATH_POINT:
4823 case XPATH_RANGE:
4824 case XPATH_LOCATIONSET:
4825 TODO
4826 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004827 case XPATH_NODESET:
4828 case XPATH_XSLT_TREE:
4829 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004830 }
4831 xmlXPathFreeObject(arg1);
4832 xmlXPathFreeObject(arg2);
4833 return(ret);
4834}
4835
William M. Brack0c022ad2002-07-12 00:56:01 +00004836/**
4837 * xmlXPathEqualValues:
4838 * @ctxt: the XPath Parser context
4839 *
4840 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4841 *
4842 * Returns 0 or 1 depending on the results of the test.
4843 */
4844int
4845xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4846 xmlXPathObjectPtr arg1, arg2, argtmp;
4847 int ret = 0;
4848
4849 arg2 = valuePop(ctxt);
4850 arg1 = valuePop(ctxt);
4851 if ((arg1 == NULL) || (arg2 == NULL)) {
4852 if (arg1 != NULL)
4853 xmlXPathFreeObject(arg1);
4854 else
4855 xmlXPathFreeObject(arg2);
4856 XP_ERROR0(XPATH_INVALID_OPERAND);
4857 }
4858
4859 if (arg1 == arg2) {
4860#ifdef DEBUG_EXPR
4861 xmlGenericError(xmlGenericErrorContext,
4862 "Equal: by pointer\n");
4863#endif
4864 return(1);
4865 }
4866
4867 /*
4868 *If either argument is a nodeset, it's a 'special case'
4869 */
4870 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4871 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4872 /*
4873 *Hack it to assure arg1 is the nodeset
4874 */
4875 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4876 argtmp = arg2;
4877 arg2 = arg1;
4878 arg1 = argtmp;
4879 }
4880 switch (arg2->type) {
4881 case XPATH_UNDEFINED:
4882#ifdef DEBUG_EXPR
4883 xmlGenericError(xmlGenericErrorContext,
4884 "Equal: undefined\n");
4885#endif
4886 break;
4887 case XPATH_NODESET:
4888 case XPATH_XSLT_TREE:
4889 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4890 break;
4891 case XPATH_BOOLEAN:
4892 if ((arg1->nodesetval == NULL) ||
4893 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4894 else
4895 ret = 1;
4896 ret = (ret == arg2->boolval);
4897 break;
4898 case XPATH_NUMBER:
4899 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4900 break;
4901 case XPATH_STRING:
4902 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4903 break;
4904 case XPATH_USERS:
4905 case XPATH_POINT:
4906 case XPATH_RANGE:
4907 case XPATH_LOCATIONSET:
4908 TODO
4909 break;
4910 }
4911 xmlXPathFreeObject(arg1);
4912 xmlXPathFreeObject(arg2);
4913 return(ret);
4914 }
4915
4916 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4917}
4918
4919/**
4920 * xmlXPathNotEqualValues:
4921 * @ctxt: the XPath Parser context
4922 *
4923 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4924 *
4925 * Returns 0 or 1 depending on the results of the test.
4926 */
4927int
4928xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4929 xmlXPathObjectPtr arg1, arg2, argtmp;
4930 int ret = 0;
4931
4932 arg2 = valuePop(ctxt);
4933 arg1 = valuePop(ctxt);
4934 if ((arg1 == NULL) || (arg2 == NULL)) {
4935 if (arg1 != NULL)
4936 xmlXPathFreeObject(arg1);
4937 else
4938 xmlXPathFreeObject(arg2);
4939 XP_ERROR0(XPATH_INVALID_OPERAND);
4940 }
4941
4942 if (arg1 == arg2) {
4943#ifdef DEBUG_EXPR
4944 xmlGenericError(xmlGenericErrorContext,
4945 "NotEqual: by pointer\n");
4946#endif
4947 return(0);
4948 }
4949
4950 /*
4951 *If either argument is a nodeset, it's a 'special case'
4952 */
4953 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4954 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4955 /*
4956 *Hack it to assure arg1 is the nodeset
4957 */
4958 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4959 argtmp = arg2;
4960 arg2 = arg1;
4961 arg1 = argtmp;
4962 }
4963 switch (arg2->type) {
4964 case XPATH_UNDEFINED:
4965#ifdef DEBUG_EXPR
4966 xmlGenericError(xmlGenericErrorContext,
4967 "NotEqual: undefined\n");
4968#endif
4969 break;
4970 case XPATH_NODESET:
4971 case XPATH_XSLT_TREE:
4972 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4973 break;
4974 case XPATH_BOOLEAN:
4975 if ((arg1->nodesetval == NULL) ||
4976 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4977 else
4978 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004979 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004980 break;
4981 case XPATH_NUMBER:
4982 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4983 break;
4984 case XPATH_STRING:
4985 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4986 break;
4987 case XPATH_USERS:
4988 case XPATH_POINT:
4989 case XPATH_RANGE:
4990 case XPATH_LOCATIONSET:
4991 TODO
4992 break;
4993 }
4994 xmlXPathFreeObject(arg1);
4995 xmlXPathFreeObject(arg2);
4996 return(ret);
4997 }
4998
4999 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5000}
Owen Taylor3473f882001-02-23 17:55:21 +00005001
5002/**
5003 * xmlXPathCompareValues:
5004 * @ctxt: the XPath Parser context
5005 * @inf: less than (1) or greater than (0)
5006 * @strict: is the comparison strict
5007 *
5008 * Implement the compare operation on XPath objects:
5009 * @arg1 < @arg2 (1, 1, ...
5010 * @arg1 <= @arg2 (1, 0, ...
5011 * @arg1 > @arg2 (0, 1, ...
5012 * @arg1 >= @arg2 (0, 0, ...
5013 *
5014 * When neither object to be compared is a node-set and the operator is
5015 * <=, <, >=, >, then the objects are compared by converted both objects
5016 * to numbers and comparing the numbers according to IEEE 754. The <
5017 * comparison will be true if and only if the first number is less than the
5018 * second number. The <= comparison will be true if and only if the first
5019 * number is less than or equal to the second number. The > comparison
5020 * will be true if and only if the first number is greater than the second
5021 * number. The >= comparison will be true if and only if the first number
5022 * is greater than or equal to the second number.
5023 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005024 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005025 */
5026int
5027xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005028 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005029 xmlXPathObjectPtr arg1, arg2;
5030
William M. Brack0c022ad2002-07-12 00:56:01 +00005031 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005032 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005033 if ((arg1 == NULL) || (arg2 == NULL)) {
5034 if (arg1 != NULL)
5035 xmlXPathFreeObject(arg1);
5036 else
5037 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005038 XP_ERROR0(XPATH_INVALID_OPERAND);
5039 }
5040
William M. Brack0c022ad2002-07-12 00:56:01 +00005041 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5042 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5043 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5044 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005045 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005046 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005047 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005048 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5049 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005050 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005051 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5052 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005053 }
5054 }
5055 return(ret);
5056 }
5057
5058 if (arg1->type != XPATH_NUMBER) {
5059 valuePush(ctxt, arg1);
5060 xmlXPathNumberFunction(ctxt, 1);
5061 arg1 = valuePop(ctxt);
5062 }
5063 if (arg1->type != XPATH_NUMBER) {
5064 xmlXPathFreeObject(arg1);
5065 xmlXPathFreeObject(arg2);
5066 XP_ERROR0(XPATH_INVALID_OPERAND);
5067 }
5068 if (arg2->type != XPATH_NUMBER) {
5069 valuePush(ctxt, arg2);
5070 xmlXPathNumberFunction(ctxt, 1);
5071 arg2 = valuePop(ctxt);
5072 }
5073 if (arg2->type != XPATH_NUMBER) {
5074 xmlXPathFreeObject(arg1);
5075 xmlXPathFreeObject(arg2);
5076 XP_ERROR0(XPATH_INVALID_OPERAND);
5077 }
5078 /*
5079 * Add tests for infinity and nan
5080 * => feedback on 3.4 for Inf and NaN
5081 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005082 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005083 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005084 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005085 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005086 arg1i=xmlXPathIsInf(arg1->floatval);
5087 arg2i=xmlXPathIsInf(arg2->floatval);
5088 if (inf && strict) {
5089 if ((arg1i == -1 && arg2i != -1) ||
5090 (arg2i == 1 && arg1i != 1)) {
5091 ret = 1;
5092 } else if (arg1i == 0 && arg2i == 0) {
5093 ret = (arg1->floatval < arg2->floatval);
5094 } else {
5095 ret = 0;
5096 }
5097 }
5098 else if (inf && !strict) {
5099 if (arg1i == -1 || arg2i == 1) {
5100 ret = 1;
5101 } else if (arg1i == 0 && arg2i == 0) {
5102 ret = (arg1->floatval <= arg2->floatval);
5103 } else {
5104 ret = 0;
5105 }
5106 }
5107 else if (!inf && strict) {
5108 if ((arg1i == 1 && arg2i != 1) ||
5109 (arg2i == -1 && arg1i != -1)) {
5110 ret = 1;
5111 } else if (arg1i == 0 && arg2i == 0) {
5112 ret = (arg1->floatval > arg2->floatval);
5113 } else {
5114 ret = 0;
5115 }
5116 }
5117 else if (!inf && !strict) {
5118 if (arg1i == 1 || arg2i == -1) {
5119 ret = 1;
5120 } else if (arg1i == 0 && arg2i == 0) {
5121 ret = (arg1->floatval >= arg2->floatval);
5122 } else {
5123 ret = 0;
5124 }
5125 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005126 }
Owen Taylor3473f882001-02-23 17:55:21 +00005127 xmlXPathFreeObject(arg1);
5128 xmlXPathFreeObject(arg2);
5129 return(ret);
5130}
5131
5132/**
5133 * xmlXPathValueFlipSign:
5134 * @ctxt: the XPath Parser context
5135 *
5136 * Implement the unary - operation on an XPath object
5137 * The numeric operators convert their operands to numbers as if
5138 * by calling the number function.
5139 */
5140void
5141xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005142 CAST_TO_NUMBER;
5143 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005144 if (xmlXPathIsNaN(ctxt->value->floatval))
5145 ctxt->value->floatval=xmlXPathNAN;
5146 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5147 ctxt->value->floatval=xmlXPathNINF;
5148 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5149 ctxt->value->floatval=xmlXPathPINF;
5150 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005151 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5152 ctxt->value->floatval = xmlXPathNZERO;
5153 else
5154 ctxt->value->floatval = 0;
5155 }
5156 else
5157 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005158}
5159
5160/**
5161 * xmlXPathAddValues:
5162 * @ctxt: the XPath Parser context
5163 *
5164 * Implement the add operation on XPath objects:
5165 * The numeric operators convert their operands to numbers as if
5166 * by calling the number function.
5167 */
5168void
5169xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5170 xmlXPathObjectPtr arg;
5171 double val;
5172
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005173 arg = valuePop(ctxt);
5174 if (arg == NULL)
5175 XP_ERROR(XPATH_INVALID_OPERAND);
5176 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005177 xmlXPathFreeObject(arg);
5178
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005179 CAST_TO_NUMBER;
5180 CHECK_TYPE(XPATH_NUMBER);
5181 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005182}
5183
5184/**
5185 * xmlXPathSubValues:
5186 * @ctxt: the XPath Parser context
5187 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005188 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005189 * The numeric operators convert their operands to numbers as if
5190 * by calling the number function.
5191 */
5192void
5193xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5194 xmlXPathObjectPtr arg;
5195 double val;
5196
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005197 arg = valuePop(ctxt);
5198 if (arg == NULL)
5199 XP_ERROR(XPATH_INVALID_OPERAND);
5200 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005201 xmlXPathFreeObject(arg);
5202
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005203 CAST_TO_NUMBER;
5204 CHECK_TYPE(XPATH_NUMBER);
5205 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005206}
5207
5208/**
5209 * xmlXPathMultValues:
5210 * @ctxt: the XPath Parser context
5211 *
5212 * Implement the multiply operation on XPath objects:
5213 * The numeric operators convert their operands to numbers as if
5214 * by calling the number function.
5215 */
5216void
5217xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5218 xmlXPathObjectPtr arg;
5219 double val;
5220
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005221 arg = valuePop(ctxt);
5222 if (arg == NULL)
5223 XP_ERROR(XPATH_INVALID_OPERAND);
5224 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005225 xmlXPathFreeObject(arg);
5226
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005227 CAST_TO_NUMBER;
5228 CHECK_TYPE(XPATH_NUMBER);
5229 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005230}
5231
5232/**
5233 * xmlXPathDivValues:
5234 * @ctxt: the XPath Parser context
5235 *
5236 * Implement the div operation on XPath objects @arg1 / @arg2:
5237 * The numeric operators convert their operands to numbers as if
5238 * by calling the number function.
5239 */
5240void
5241xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5242 xmlXPathObjectPtr arg;
5243 double val;
5244
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005245 arg = valuePop(ctxt);
5246 if (arg == NULL)
5247 XP_ERROR(XPATH_INVALID_OPERAND);
5248 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005249 xmlXPathFreeObject(arg);
5250
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005251 CAST_TO_NUMBER;
5252 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005253 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5254 ctxt->value->floatval = xmlXPathNAN;
5255 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005256 if (ctxt->value->floatval == 0)
5257 ctxt->value->floatval = xmlXPathNAN;
5258 else if (ctxt->value->floatval > 0)
5259 ctxt->value->floatval = xmlXPathNINF;
5260 else if (ctxt->value->floatval < 0)
5261 ctxt->value->floatval = xmlXPathPINF;
5262 }
5263 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005264 if (ctxt->value->floatval == 0)
5265 ctxt->value->floatval = xmlXPathNAN;
5266 else if (ctxt->value->floatval > 0)
5267 ctxt->value->floatval = xmlXPathPINF;
5268 else if (ctxt->value->floatval < 0)
5269 ctxt->value->floatval = xmlXPathNINF;
5270 } else
5271 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005272}
5273
5274/**
5275 * xmlXPathModValues:
5276 * @ctxt: the XPath Parser context
5277 *
5278 * Implement the mod operation on XPath objects: @arg1 / @arg2
5279 * The numeric operators convert their operands to numbers as if
5280 * by calling the number function.
5281 */
5282void
5283xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5284 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005285 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005286
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005287 arg = valuePop(ctxt);
5288 if (arg == NULL)
5289 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005290 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005291 xmlXPathFreeObject(arg);
5292
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005293 CAST_TO_NUMBER;
5294 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005295 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005296 if (arg2 == 0)
5297 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005298 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005299 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005300 }
Owen Taylor3473f882001-02-23 17:55:21 +00005301}
5302
5303/************************************************************************
5304 * *
5305 * The traversal functions *
5306 * *
5307 ************************************************************************/
5308
Owen Taylor3473f882001-02-23 17:55:21 +00005309/*
5310 * A traversal function enumerates nodes along an axis.
5311 * Initially it must be called with NULL, and it indicates
5312 * termination on the axis by returning NULL.
5313 */
5314typedef xmlNodePtr (*xmlXPathTraversalFunction)
5315 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5316
5317/**
5318 * xmlXPathNextSelf:
5319 * @ctxt: the XPath Parser context
5320 * @cur: the current node in the traversal
5321 *
5322 * Traversal function for the "self" direction
5323 * The self axis contains just the context node itself
5324 *
5325 * Returns the next element following that axis
5326 */
5327xmlNodePtr
5328xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5329 if (cur == NULL)
5330 return(ctxt->context->node);
5331 return(NULL);
5332}
5333
5334/**
5335 * xmlXPathNextChild:
5336 * @ctxt: the XPath Parser context
5337 * @cur: the current node in the traversal
5338 *
5339 * Traversal function for the "child" direction
5340 * The child axis contains the children of the context node in document order.
5341 *
5342 * Returns the next element following that axis
5343 */
5344xmlNodePtr
5345xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5346 if (cur == NULL) {
5347 if (ctxt->context->node == NULL) return(NULL);
5348 switch (ctxt->context->node->type) {
5349 case XML_ELEMENT_NODE:
5350 case XML_TEXT_NODE:
5351 case XML_CDATA_SECTION_NODE:
5352 case XML_ENTITY_REF_NODE:
5353 case XML_ENTITY_NODE:
5354 case XML_PI_NODE:
5355 case XML_COMMENT_NODE:
5356 case XML_NOTATION_NODE:
5357 case XML_DTD_NODE:
5358 return(ctxt->context->node->children);
5359 case XML_DOCUMENT_NODE:
5360 case XML_DOCUMENT_TYPE_NODE:
5361 case XML_DOCUMENT_FRAG_NODE:
5362 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005363#ifdef LIBXML_DOCB_ENABLED
5364 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005365#endif
5366 return(((xmlDocPtr) ctxt->context->node)->children);
5367 case XML_ELEMENT_DECL:
5368 case XML_ATTRIBUTE_DECL:
5369 case XML_ENTITY_DECL:
5370 case XML_ATTRIBUTE_NODE:
5371 case XML_NAMESPACE_DECL:
5372 case XML_XINCLUDE_START:
5373 case XML_XINCLUDE_END:
5374 return(NULL);
5375 }
5376 return(NULL);
5377 }
5378 if ((cur->type == XML_DOCUMENT_NODE) ||
5379 (cur->type == XML_HTML_DOCUMENT_NODE))
5380 return(NULL);
5381 return(cur->next);
5382}
5383
5384/**
5385 * xmlXPathNextDescendant:
5386 * @ctxt: the XPath Parser context
5387 * @cur: the current node in the traversal
5388 *
5389 * Traversal function for the "descendant" direction
5390 * the descendant axis contains the descendants of the context node in document
5391 * order; a descendant is a child or a child of a child and so on.
5392 *
5393 * Returns the next element following that axis
5394 */
5395xmlNodePtr
5396xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5397 if (cur == NULL) {
5398 if (ctxt->context->node == NULL)
5399 return(NULL);
5400 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5401 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5402 return(NULL);
5403
5404 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5405 return(ctxt->context->doc->children);
5406 return(ctxt->context->node->children);
5407 }
5408
Daniel Veillard567e1b42001-08-01 15:53:47 +00005409 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005410 /*
5411 * Do not descend on entities declarations
5412 */
5413 if (cur->children->type != XML_ENTITY_DECL) {
5414 cur = cur->children;
5415 /*
5416 * Skip DTDs
5417 */
5418 if (cur->type != XML_DTD_NODE)
5419 return(cur);
5420 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005421 }
5422
5423 if (cur == ctxt->context->node) return(NULL);
5424
Daniel Veillard68e9e742002-11-16 15:35:11 +00005425 while (cur->next != NULL) {
5426 cur = cur->next;
5427 if ((cur->type != XML_ENTITY_DECL) &&
5428 (cur->type != XML_DTD_NODE))
5429 return(cur);
5430 }
Owen Taylor3473f882001-02-23 17:55:21 +00005431
5432 do {
5433 cur = cur->parent;
5434 if (cur == NULL) return(NULL);
5435 if (cur == ctxt->context->node) return(NULL);
5436 if (cur->next != NULL) {
5437 cur = cur->next;
5438 return(cur);
5439 }
5440 } while (cur != NULL);
5441 return(cur);
5442}
5443
5444/**
5445 * xmlXPathNextDescendantOrSelf:
5446 * @ctxt: the XPath Parser context
5447 * @cur: the current node in the traversal
5448 *
5449 * Traversal function for the "descendant-or-self" direction
5450 * the descendant-or-self axis contains the context node and the descendants
5451 * of the context node in document order; thus the context node is the first
5452 * node on the axis, and the first child of the context node is the second node
5453 * on the axis
5454 *
5455 * Returns the next element following that axis
5456 */
5457xmlNodePtr
5458xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5459 if (cur == NULL) {
5460 if (ctxt->context->node == NULL)
5461 return(NULL);
5462 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5463 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5464 return(NULL);
5465 return(ctxt->context->node);
5466 }
5467
5468 return(xmlXPathNextDescendant(ctxt, cur));
5469}
5470
5471/**
5472 * xmlXPathNextParent:
5473 * @ctxt: the XPath Parser context
5474 * @cur: the current node in the traversal
5475 *
5476 * Traversal function for the "parent" direction
5477 * The parent axis contains the parent of the context node, if there is one.
5478 *
5479 * Returns the next element following that axis
5480 */
5481xmlNodePtr
5482xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5483 /*
5484 * the parent of an attribute or namespace node is the element
5485 * to which the attribute or namespace node is attached
5486 * Namespace handling !!!
5487 */
5488 if (cur == NULL) {
5489 if (ctxt->context->node == NULL) return(NULL);
5490 switch (ctxt->context->node->type) {
5491 case XML_ELEMENT_NODE:
5492 case XML_TEXT_NODE:
5493 case XML_CDATA_SECTION_NODE:
5494 case XML_ENTITY_REF_NODE:
5495 case XML_ENTITY_NODE:
5496 case XML_PI_NODE:
5497 case XML_COMMENT_NODE:
5498 case XML_NOTATION_NODE:
5499 case XML_DTD_NODE:
5500 case XML_ELEMENT_DECL:
5501 case XML_ATTRIBUTE_DECL:
5502 case XML_XINCLUDE_START:
5503 case XML_XINCLUDE_END:
5504 case XML_ENTITY_DECL:
5505 if (ctxt->context->node->parent == NULL)
5506 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005507 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005508 ((ctxt->context->node->parent->name[0] == ' ') ||
5509 (xmlStrEqual(ctxt->context->node->parent->name,
5510 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005511 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005512 return(ctxt->context->node->parent);
5513 case XML_ATTRIBUTE_NODE: {
5514 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5515
5516 return(att->parent);
5517 }
5518 case XML_DOCUMENT_NODE:
5519 case XML_DOCUMENT_TYPE_NODE:
5520 case XML_DOCUMENT_FRAG_NODE:
5521 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005522#ifdef LIBXML_DOCB_ENABLED
5523 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005524#endif
5525 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005526 case XML_NAMESPACE_DECL: {
5527 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5528
5529 if ((ns->next != NULL) &&
5530 (ns->next->type != XML_NAMESPACE_DECL))
5531 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005532 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005533 }
Owen Taylor3473f882001-02-23 17:55:21 +00005534 }
5535 }
5536 return(NULL);
5537}
5538
5539/**
5540 * xmlXPathNextAncestor:
5541 * @ctxt: the XPath Parser context
5542 * @cur: the current node in the traversal
5543 *
5544 * Traversal function for the "ancestor" direction
5545 * the ancestor axis contains the ancestors of the context node; the ancestors
5546 * of the context node consist of the parent of context node and the parent's
5547 * parent and so on; the nodes are ordered in reverse document order; thus the
5548 * parent is the first node on the axis, and the parent's parent is the second
5549 * node on the axis
5550 *
5551 * Returns the next element following that axis
5552 */
5553xmlNodePtr
5554xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5555 /*
5556 * the parent of an attribute or namespace node is the element
5557 * to which the attribute or namespace node is attached
5558 * !!!!!!!!!!!!!
5559 */
5560 if (cur == NULL) {
5561 if (ctxt->context->node == NULL) return(NULL);
5562 switch (ctxt->context->node->type) {
5563 case XML_ELEMENT_NODE:
5564 case XML_TEXT_NODE:
5565 case XML_CDATA_SECTION_NODE:
5566 case XML_ENTITY_REF_NODE:
5567 case XML_ENTITY_NODE:
5568 case XML_PI_NODE:
5569 case XML_COMMENT_NODE:
5570 case XML_DTD_NODE:
5571 case XML_ELEMENT_DECL:
5572 case XML_ATTRIBUTE_DECL:
5573 case XML_ENTITY_DECL:
5574 case XML_NOTATION_NODE:
5575 case XML_XINCLUDE_START:
5576 case XML_XINCLUDE_END:
5577 if (ctxt->context->node->parent == NULL)
5578 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005579 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005580 ((ctxt->context->node->parent->name[0] == ' ') ||
5581 (xmlStrEqual(ctxt->context->node->parent->name,
5582 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005583 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005584 return(ctxt->context->node->parent);
5585 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005586 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005587
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005588 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005589 }
5590 case XML_DOCUMENT_NODE:
5591 case XML_DOCUMENT_TYPE_NODE:
5592 case XML_DOCUMENT_FRAG_NODE:
5593 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005594#ifdef LIBXML_DOCB_ENABLED
5595 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005596#endif
5597 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005598 case XML_NAMESPACE_DECL: {
5599 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5600
5601 if ((ns->next != NULL) &&
5602 (ns->next->type != XML_NAMESPACE_DECL))
5603 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005604 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005605 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005606 }
Owen Taylor3473f882001-02-23 17:55:21 +00005607 }
5608 return(NULL);
5609 }
5610 if (cur == ctxt->context->doc->children)
5611 return((xmlNodePtr) ctxt->context->doc);
5612 if (cur == (xmlNodePtr) ctxt->context->doc)
5613 return(NULL);
5614 switch (cur->type) {
5615 case XML_ELEMENT_NODE:
5616 case XML_TEXT_NODE:
5617 case XML_CDATA_SECTION_NODE:
5618 case XML_ENTITY_REF_NODE:
5619 case XML_ENTITY_NODE:
5620 case XML_PI_NODE:
5621 case XML_COMMENT_NODE:
5622 case XML_NOTATION_NODE:
5623 case XML_DTD_NODE:
5624 case XML_ELEMENT_DECL:
5625 case XML_ATTRIBUTE_DECL:
5626 case XML_ENTITY_DECL:
5627 case XML_XINCLUDE_START:
5628 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005629 if (cur->parent == NULL)
5630 return(NULL);
5631 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005632 ((cur->parent->name[0] == ' ') ||
5633 (xmlStrEqual(cur->parent->name,
5634 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005635 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005636 return(cur->parent);
5637 case XML_ATTRIBUTE_NODE: {
5638 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5639
5640 return(att->parent);
5641 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005642 case XML_NAMESPACE_DECL: {
5643 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5644
5645 if ((ns->next != NULL) &&
5646 (ns->next->type != XML_NAMESPACE_DECL))
5647 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005648 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005649 return(NULL);
5650 }
Owen Taylor3473f882001-02-23 17:55:21 +00005651 case XML_DOCUMENT_NODE:
5652 case XML_DOCUMENT_TYPE_NODE:
5653 case XML_DOCUMENT_FRAG_NODE:
5654 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005655#ifdef LIBXML_DOCB_ENABLED
5656 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005657#endif
5658 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005659 }
5660 return(NULL);
5661}
5662
5663/**
5664 * xmlXPathNextAncestorOrSelf:
5665 * @ctxt: the XPath Parser context
5666 * @cur: the current node in the traversal
5667 *
5668 * Traversal function for the "ancestor-or-self" direction
5669 * he ancestor-or-self axis contains the context node and ancestors of
5670 * the context node in reverse document order; thus the context node is
5671 * the first node on the axis, and the context node's parent the second;
5672 * parent here is defined the same as with the parent axis.
5673 *
5674 * Returns the next element following that axis
5675 */
5676xmlNodePtr
5677xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5678 if (cur == NULL)
5679 return(ctxt->context->node);
5680 return(xmlXPathNextAncestor(ctxt, cur));
5681}
5682
5683/**
5684 * xmlXPathNextFollowingSibling:
5685 * @ctxt: the XPath Parser context
5686 * @cur: the current node in the traversal
5687 *
5688 * Traversal function for the "following-sibling" direction
5689 * The following-sibling axis contains the following siblings of the context
5690 * node in document order.
5691 *
5692 * Returns the next element following that axis
5693 */
5694xmlNodePtr
5695xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5696 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5697 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5698 return(NULL);
5699 if (cur == (xmlNodePtr) ctxt->context->doc)
5700 return(NULL);
5701 if (cur == NULL)
5702 return(ctxt->context->node->next);
5703 return(cur->next);
5704}
5705
5706/**
5707 * xmlXPathNextPrecedingSibling:
5708 * @ctxt: the XPath Parser context
5709 * @cur: the current node in the traversal
5710 *
5711 * Traversal function for the "preceding-sibling" direction
5712 * The preceding-sibling axis contains the preceding siblings of the context
5713 * node in reverse document order; the first preceding sibling is first on the
5714 * axis; the sibling preceding that node is the second on the axis and so on.
5715 *
5716 * Returns the next element following that axis
5717 */
5718xmlNodePtr
5719xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5720 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5721 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5722 return(NULL);
5723 if (cur == (xmlNodePtr) ctxt->context->doc)
5724 return(NULL);
5725 if (cur == NULL)
5726 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005727 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5728 cur = cur->prev;
5729 if (cur == NULL)
5730 return(ctxt->context->node->prev);
5731 }
Owen Taylor3473f882001-02-23 17:55:21 +00005732 return(cur->prev);
5733}
5734
5735/**
5736 * xmlXPathNextFollowing:
5737 * @ctxt: the XPath Parser context
5738 * @cur: the current node in the traversal
5739 *
5740 * Traversal function for the "following" direction
5741 * The following axis contains all nodes in the same document as the context
5742 * node that are after the context node in document order, excluding any
5743 * descendants and excluding attribute nodes and namespace nodes; the nodes
5744 * are ordered in document order
5745 *
5746 * Returns the next element following that axis
5747 */
5748xmlNodePtr
5749xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5750 if (cur != NULL && cur->children != NULL)
5751 return cur->children ;
5752 if (cur == NULL) cur = ctxt->context->node;
5753 if (cur == NULL) return(NULL) ; /* ERROR */
5754 if (cur->next != NULL) return(cur->next) ;
5755 do {
5756 cur = cur->parent;
5757 if (cur == NULL) return(NULL);
5758 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5759 if (cur->next != NULL) return(cur->next);
5760 } while (cur != NULL);
5761 return(cur);
5762}
5763
5764/*
5765 * xmlXPathIsAncestor:
5766 * @ancestor: the ancestor node
5767 * @node: the current node
5768 *
5769 * Check that @ancestor is a @node's ancestor
5770 *
5771 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5772 */
5773static int
5774xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5775 if ((ancestor == NULL) || (node == NULL)) return(0);
5776 /* nodes need to be in the same document */
5777 if (ancestor->doc != node->doc) return(0);
5778 /* avoid searching if ancestor or node is the root node */
5779 if (ancestor == (xmlNodePtr) node->doc) return(1);
5780 if (node == (xmlNodePtr) ancestor->doc) return(0);
5781 while (node->parent != NULL) {
5782 if (node->parent == ancestor)
5783 return(1);
5784 node = node->parent;
5785 }
5786 return(0);
5787}
5788
5789/**
5790 * xmlXPathNextPreceding:
5791 * @ctxt: the XPath Parser context
5792 * @cur: the current node in the traversal
5793 *
5794 * Traversal function for the "preceding" direction
5795 * the preceding axis contains all nodes in the same document as the context
5796 * node that are before the context node in document order, excluding any
5797 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5798 * ordered in reverse document order
5799 *
5800 * Returns the next element following that axis
5801 */
5802xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005803xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5804{
Owen Taylor3473f882001-02-23 17:55:21 +00005805 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005806 cur = ctxt->context->node;
5807 if (cur == NULL)
5808 return (NULL);
5809 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5810 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005811 do {
5812 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005813 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5814 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005815 }
5816
5817 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005818 if (cur == NULL)
5819 return (NULL);
5820 if (cur == ctxt->context->doc->children)
5821 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005822 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005823 return (cur);
5824}
5825
5826/**
5827 * xmlXPathNextPrecedingInternal:
5828 * @ctxt: the XPath Parser context
5829 * @cur: the current node in the traversal
5830 *
5831 * Traversal function for the "preceding" direction
5832 * the preceding axis contains all nodes in the same document as the context
5833 * node that are before the context node in document order, excluding any
5834 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5835 * ordered in reverse document order
5836 * This is a faster implementation but internal only since it requires a
5837 * state kept in the parser context: ctxt->ancestor.
5838 *
5839 * Returns the next element following that axis
5840 */
5841static xmlNodePtr
5842xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5843 xmlNodePtr cur)
5844{
5845 if (cur == NULL) {
5846 cur = ctxt->context->node;
5847 if (cur == NULL)
5848 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005849 if (cur->type == XML_NAMESPACE_DECL)
5850 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005851 ctxt->ancestor = cur->parent;
5852 }
5853 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5854 cur = cur->prev;
5855 while (cur->prev == NULL) {
5856 cur = cur->parent;
5857 if (cur == NULL)
5858 return (NULL);
5859 if (cur == ctxt->context->doc->children)
5860 return (NULL);
5861 if (cur != ctxt->ancestor)
5862 return (cur);
5863 ctxt->ancestor = cur->parent;
5864 }
5865 cur = cur->prev;
5866 while (cur->last != NULL)
5867 cur = cur->last;
5868 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005869}
5870
5871/**
5872 * xmlXPathNextNamespace:
5873 * @ctxt: the XPath Parser context
5874 * @cur: the current attribute in the traversal
5875 *
5876 * Traversal function for the "namespace" direction
5877 * the namespace axis contains the namespace nodes of the context node;
5878 * the order of nodes on this axis is implementation-defined; the axis will
5879 * be empty unless the context node is an element
5880 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005881 * We keep the XML namespace node at the end of the list.
5882 *
Owen Taylor3473f882001-02-23 17:55:21 +00005883 * Returns the next element following that axis
5884 */
5885xmlNodePtr
5886xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5887 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005888 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005889 if (ctxt->context->tmpNsList != NULL)
5890 xmlFree(ctxt->context->tmpNsList);
5891 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005892 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005893 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005894 if (ctxt->context->tmpNsList != NULL) {
5895 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5896 ctxt->context->tmpNsNr++;
5897 }
5898 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005899 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005900 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005901 if (ctxt->context->tmpNsNr > 0) {
5902 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5903 } else {
5904 if (ctxt->context->tmpNsList != NULL)
5905 xmlFree(ctxt->context->tmpNsList);
5906 ctxt->context->tmpNsList = NULL;
5907 return(NULL);
5908 }
Owen Taylor3473f882001-02-23 17:55:21 +00005909}
5910
5911/**
5912 * xmlXPathNextAttribute:
5913 * @ctxt: the XPath Parser context
5914 * @cur: the current attribute in the traversal
5915 *
5916 * Traversal function for the "attribute" direction
5917 * TODO: support DTD inherited default attributes
5918 *
5919 * Returns the next element following that axis
5920 */
5921xmlNodePtr
5922xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005923 if (ctxt->context->node == NULL)
5924 return(NULL);
5925 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5926 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005927 if (cur == NULL) {
5928 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5929 return(NULL);
5930 return((xmlNodePtr)ctxt->context->node->properties);
5931 }
5932 return((xmlNodePtr)cur->next);
5933}
5934
5935/************************************************************************
5936 * *
5937 * NodeTest Functions *
5938 * *
5939 ************************************************************************/
5940
Owen Taylor3473f882001-02-23 17:55:21 +00005941#define IS_FUNCTION 200
5942
Owen Taylor3473f882001-02-23 17:55:21 +00005943
5944/************************************************************************
5945 * *
5946 * Implicit tree core function library *
5947 * *
5948 ************************************************************************/
5949
5950/**
5951 * xmlXPathRoot:
5952 * @ctxt: the XPath Parser context
5953 *
5954 * Initialize the context to the root of the document
5955 */
5956void
5957xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5958 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5959 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5960}
5961
5962/************************************************************************
5963 * *
5964 * The explicit core function library *
5965 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5966 * *
5967 ************************************************************************/
5968
5969
5970/**
5971 * xmlXPathLastFunction:
5972 * @ctxt: the XPath Parser context
5973 * @nargs: the number of arguments
5974 *
5975 * Implement the last() XPath function
5976 * number last()
5977 * The last function returns the number of nodes in the context node list.
5978 */
5979void
5980xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5981 CHECK_ARITY(0);
5982 if (ctxt->context->contextSize >= 0) {
5983 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5984#ifdef DEBUG_EXPR
5985 xmlGenericError(xmlGenericErrorContext,
5986 "last() : %d\n", ctxt->context->contextSize);
5987#endif
5988 } else {
5989 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5990 }
5991}
5992
5993/**
5994 * xmlXPathPositionFunction:
5995 * @ctxt: the XPath Parser context
5996 * @nargs: the number of arguments
5997 *
5998 * Implement the position() XPath function
5999 * number position()
6000 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006001 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00006002 * will be equal to last().
6003 */
6004void
6005xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6006 CHECK_ARITY(0);
6007 if (ctxt->context->proximityPosition >= 0) {
6008 valuePush(ctxt,
6009 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6010#ifdef DEBUG_EXPR
6011 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6012 ctxt->context->proximityPosition);
6013#endif
6014 } else {
6015 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6016 }
6017}
6018
6019/**
6020 * xmlXPathCountFunction:
6021 * @ctxt: the XPath Parser context
6022 * @nargs: the number of arguments
6023 *
6024 * Implement the count() XPath function
6025 * number count(node-set)
6026 */
6027void
6028xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6029 xmlXPathObjectPtr cur;
6030
6031 CHECK_ARITY(1);
6032 if ((ctxt->value == NULL) ||
6033 ((ctxt->value->type != XPATH_NODESET) &&
6034 (ctxt->value->type != XPATH_XSLT_TREE)))
6035 XP_ERROR(XPATH_INVALID_TYPE);
6036 cur = valuePop(ctxt);
6037
Daniel Veillard911f49a2001-04-07 15:39:35 +00006038 if ((cur == NULL) || (cur->nodesetval == NULL))
6039 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006040 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006041 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006042 } else {
6043 if ((cur->nodesetval->nodeNr != 1) ||
6044 (cur->nodesetval->nodeTab == NULL)) {
6045 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6046 } else {
6047 xmlNodePtr tmp;
6048 int i = 0;
6049
6050 tmp = cur->nodesetval->nodeTab[0];
6051 if (tmp != NULL) {
6052 tmp = tmp->children;
6053 while (tmp != NULL) {
6054 tmp = tmp->next;
6055 i++;
6056 }
6057 }
6058 valuePush(ctxt, xmlXPathNewFloat((double) i));
6059 }
6060 }
Owen Taylor3473f882001-02-23 17:55:21 +00006061 xmlXPathFreeObject(cur);
6062}
6063
6064/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006065 * xmlXPathGetElementsByIds:
6066 * @doc: the document
6067 * @ids: a whitespace separated list of IDs
6068 *
6069 * Selects elements by their unique ID.
6070 *
6071 * Returns a node-set of selected elements.
6072 */
6073static xmlNodeSetPtr
6074xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6075 xmlNodeSetPtr ret;
6076 const xmlChar *cur = ids;
6077 xmlChar *ID;
6078 xmlAttrPtr attr;
6079 xmlNodePtr elem = NULL;
6080
Daniel Veillard7a985a12003-07-06 17:57:42 +00006081 if (ids == NULL) return(NULL);
6082
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006083 ret = xmlXPathNodeSetCreate(NULL);
6084
William M. Brack76e95df2003-10-18 16:20:14 +00006085 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006086 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006087 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006088 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006089
6090 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006091 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00006092 /*
6093 * We used to check the fact that the value passed
6094 * was an NCName, but this generated much troubles for
6095 * me and Aleksey Sanin, people blatantly violated that
6096 * constaint, like Visa3D spec.
6097 * if (xmlValidateNCName(ID, 1) == 0)
6098 */
6099 attr = xmlGetID(doc, ID);
6100 if (attr != NULL) {
6101 if (attr->type == XML_ATTRIBUTE_NODE)
6102 elem = attr->parent;
6103 else if (attr->type == XML_ELEMENT_NODE)
6104 elem = (xmlNodePtr) attr;
6105 else
6106 elem = NULL;
6107 if (elem != NULL)
6108 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00006109 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006110 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006111 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006112
William M. Brack76e95df2003-10-18 16:20:14 +00006113 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006114 ids = cur;
6115 }
6116 return(ret);
6117}
6118
6119/**
Owen Taylor3473f882001-02-23 17:55:21 +00006120 * xmlXPathIdFunction:
6121 * @ctxt: the XPath Parser context
6122 * @nargs: the number of arguments
6123 *
6124 * Implement the id() XPath function
6125 * node-set id(object)
6126 * The id function selects elements by their unique ID
6127 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6128 * then the result is the union of the result of applying id to the
6129 * string value of each of the nodes in the argument node-set. When the
6130 * argument to id is of any other type, the argument is converted to a
6131 * string as if by a call to the string function; the string is split
6132 * into a whitespace-separated list of tokens (whitespace is any sequence
6133 * of characters matching the production S); the result is a node-set
6134 * containing the elements in the same document as the context node that
6135 * have a unique ID equal to any of the tokens in the list.
6136 */
6137void
6138xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006139 xmlChar *tokens;
6140 xmlNodeSetPtr ret;
6141 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006142
6143 CHECK_ARITY(1);
6144 obj = valuePop(ctxt);
6145 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006146 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006147 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006148 int i;
6149
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006150 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006151
Daniel Veillard911f49a2001-04-07 15:39:35 +00006152 if (obj->nodesetval != NULL) {
6153 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006154 tokens =
6155 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6156 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6157 ret = xmlXPathNodeSetMerge(ret, ns);
6158 xmlXPathFreeNodeSet(ns);
6159 if (tokens != NULL)
6160 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006161 }
Owen Taylor3473f882001-02-23 17:55:21 +00006162 }
6163
6164 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006165 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006166 return;
6167 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006168 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006169
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006170 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6171 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006172
Owen Taylor3473f882001-02-23 17:55:21 +00006173 xmlXPathFreeObject(obj);
6174 return;
6175}
6176
6177/**
6178 * xmlXPathLocalNameFunction:
6179 * @ctxt: the XPath Parser context
6180 * @nargs: the number of arguments
6181 *
6182 * Implement the local-name() XPath function
6183 * string local-name(node-set?)
6184 * The local-name function returns a string containing the local part
6185 * of the name of the node in the argument node-set that is first in
6186 * document order. If the node-set is empty or the first node has no
6187 * name, an empty string is returned. If the argument is omitted it
6188 * defaults to the context node.
6189 */
6190void
6191xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6192 xmlXPathObjectPtr cur;
6193
6194 if (nargs == 0) {
6195 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6196 nargs = 1;
6197 }
6198
6199 CHECK_ARITY(1);
6200 if ((ctxt->value == NULL) ||
6201 ((ctxt->value->type != XPATH_NODESET) &&
6202 (ctxt->value->type != XPATH_XSLT_TREE)))
6203 XP_ERROR(XPATH_INVALID_TYPE);
6204 cur = valuePop(ctxt);
6205
Daniel Veillard911f49a2001-04-07 15:39:35 +00006206 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006207 valuePush(ctxt, xmlXPathNewCString(""));
6208 } else {
6209 int i = 0; /* Should be first in document order !!!!! */
6210 switch (cur->nodesetval->nodeTab[i]->type) {
6211 case XML_ELEMENT_NODE:
6212 case XML_ATTRIBUTE_NODE:
6213 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006214 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6215 valuePush(ctxt, xmlXPathNewCString(""));
6216 else
6217 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006218 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6219 break;
6220 case XML_NAMESPACE_DECL:
6221 valuePush(ctxt, xmlXPathNewString(
6222 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6223 break;
6224 default:
6225 valuePush(ctxt, xmlXPathNewCString(""));
6226 }
6227 }
6228 xmlXPathFreeObject(cur);
6229}
6230
6231/**
6232 * xmlXPathNamespaceURIFunction:
6233 * @ctxt: the XPath Parser context
6234 * @nargs: the number of arguments
6235 *
6236 * Implement the namespace-uri() XPath function
6237 * string namespace-uri(node-set?)
6238 * The namespace-uri function returns a string containing the
6239 * namespace URI of the expanded name of the node in the argument
6240 * node-set that is first in document order. If the node-set is empty,
6241 * the first node has no name, or the expanded name has no namespace
6242 * URI, an empty string is returned. If the argument is omitted it
6243 * defaults to the context node.
6244 */
6245void
6246xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6247 xmlXPathObjectPtr cur;
6248
6249 if (nargs == 0) {
6250 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6251 nargs = 1;
6252 }
6253 CHECK_ARITY(1);
6254 if ((ctxt->value == NULL) ||
6255 ((ctxt->value->type != XPATH_NODESET) &&
6256 (ctxt->value->type != XPATH_XSLT_TREE)))
6257 XP_ERROR(XPATH_INVALID_TYPE);
6258 cur = valuePop(ctxt);
6259
Daniel Veillard911f49a2001-04-07 15:39:35 +00006260 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006261 valuePush(ctxt, xmlXPathNewCString(""));
6262 } else {
6263 int i = 0; /* Should be first in document order !!!!! */
6264 switch (cur->nodesetval->nodeTab[i]->type) {
6265 case XML_ELEMENT_NODE:
6266 case XML_ATTRIBUTE_NODE:
6267 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6268 valuePush(ctxt, xmlXPathNewCString(""));
6269 else
6270 valuePush(ctxt, xmlXPathNewString(
6271 cur->nodesetval->nodeTab[i]->ns->href));
6272 break;
6273 default:
6274 valuePush(ctxt, xmlXPathNewCString(""));
6275 }
6276 }
6277 xmlXPathFreeObject(cur);
6278}
6279
6280/**
6281 * xmlXPathNameFunction:
6282 * @ctxt: the XPath Parser context
6283 * @nargs: the number of arguments
6284 *
6285 * Implement the name() XPath function
6286 * string name(node-set?)
6287 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006288 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006289 * order. The QName must represent the name with respect to the namespace
6290 * declarations in effect on the node whose name is being represented.
6291 * Typically, this will be the form in which the name occurred in the XML
6292 * source. This need not be the case if there are namespace declarations
6293 * in effect on the node that associate multiple prefixes with the same
6294 * namespace. However, an implementation may include information about
6295 * the original prefix in its representation of nodes; in this case, an
6296 * implementation can ensure that the returned string is always the same
6297 * as the QName used in the XML source. If the argument it omitted it
6298 * defaults to the context node.
6299 * Libxml keep the original prefix so the "real qualified name" used is
6300 * returned.
6301 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006302static void
Daniel Veillard04383752001-07-08 14:27:15 +00006303xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6304{
Owen Taylor3473f882001-02-23 17:55:21 +00006305 xmlXPathObjectPtr cur;
6306
6307 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006308 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6309 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006310 }
6311
6312 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006313 if ((ctxt->value == NULL) ||
6314 ((ctxt->value->type != XPATH_NODESET) &&
6315 (ctxt->value->type != XPATH_XSLT_TREE)))
6316 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006317 cur = valuePop(ctxt);
6318
Daniel Veillard911f49a2001-04-07 15:39:35 +00006319 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006320 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006321 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006322 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006323
Daniel Veillard04383752001-07-08 14:27:15 +00006324 switch (cur->nodesetval->nodeTab[i]->type) {
6325 case XML_ELEMENT_NODE:
6326 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006327 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6328 valuePush(ctxt, xmlXPathNewCString(""));
6329 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6330 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006331 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006332 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006333
Daniel Veillard652d8a92003-02-04 19:28:49 +00006334 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006335 xmlChar *fullname;
6336
6337 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6338 cur->nodesetval->nodeTab[i]->ns->prefix,
6339 NULL, 0);
6340 if (fullname == cur->nodesetval->nodeTab[i]->name)
6341 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6342 if (fullname == NULL) {
6343 XP_ERROR(XPATH_MEMORY_ERROR);
6344 }
6345 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006346 }
6347 break;
6348 default:
6349 valuePush(ctxt,
6350 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6351 xmlXPathLocalNameFunction(ctxt, 1);
6352 }
Owen Taylor3473f882001-02-23 17:55:21 +00006353 }
6354 xmlXPathFreeObject(cur);
6355}
6356
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006357
6358/**
Owen Taylor3473f882001-02-23 17:55:21 +00006359 * xmlXPathStringFunction:
6360 * @ctxt: the XPath Parser context
6361 * @nargs: the number of arguments
6362 *
6363 * Implement the string() XPath function
6364 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006365 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006366 * - A node-set is converted to a string by returning the value of
6367 * the node in the node-set that is first in document order.
6368 * If the node-set is empty, an empty string is returned.
6369 * - A number is converted to a string as follows
6370 * + NaN is converted to the string NaN
6371 * + positive zero is converted to the string 0
6372 * + negative zero is converted to the string 0
6373 * + positive infinity is converted to the string Infinity
6374 * + negative infinity is converted to the string -Infinity
6375 * + if the number is an integer, the number is represented in
6376 * decimal form as a Number with no decimal point and no leading
6377 * zeros, preceded by a minus sign (-) if the number is negative
6378 * + otherwise, the number is represented in decimal form as a
6379 * Number including a decimal point with at least one digit
6380 * before the decimal point and at least one digit after the
6381 * decimal point, preceded by a minus sign (-) if the number
6382 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006383 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006384 * before the decimal point; beyond the one required digit
6385 * after the decimal point there must be as many, but only as
6386 * many, more digits as are needed to uniquely distinguish the
6387 * number from all other IEEE 754 numeric values.
6388 * - The boolean false value is converted to the string false.
6389 * The boolean true value is converted to the string true.
6390 *
6391 * If the argument is omitted, it defaults to a node-set with the
6392 * context node as its only member.
6393 */
6394void
6395xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6396 xmlXPathObjectPtr cur;
6397
6398 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006399 valuePush(ctxt,
6400 xmlXPathWrapString(
6401 xmlXPathCastNodeToString(ctxt->context->node)));
6402 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006403 }
6404
6405 CHECK_ARITY(1);
6406 cur = valuePop(ctxt);
6407 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006408 cur = xmlXPathConvertString(cur);
6409 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006410}
6411
6412/**
6413 * xmlXPathStringLengthFunction:
6414 * @ctxt: the XPath Parser context
6415 * @nargs: the number of arguments
6416 *
6417 * Implement the string-length() XPath function
6418 * number string-length(string?)
6419 * The string-length returns the number of characters in the string
6420 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6421 * the context node converted to a string, in other words the value
6422 * of the context node.
6423 */
6424void
6425xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6426 xmlXPathObjectPtr cur;
6427
6428 if (nargs == 0) {
6429 if (ctxt->context->node == NULL) {
6430 valuePush(ctxt, xmlXPathNewFloat(0));
6431 } else {
6432 xmlChar *content;
6433
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006434 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006435 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006436 xmlFree(content);
6437 }
6438 return;
6439 }
6440 CHECK_ARITY(1);
6441 CAST_TO_STRING;
6442 CHECK_TYPE(XPATH_STRING);
6443 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006444 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006445 xmlXPathFreeObject(cur);
6446}
6447
6448/**
6449 * xmlXPathConcatFunction:
6450 * @ctxt: the XPath Parser context
6451 * @nargs: the number of arguments
6452 *
6453 * Implement the concat() XPath function
6454 * string concat(string, string, string*)
6455 * The concat function returns the concatenation of its arguments.
6456 */
6457void
6458xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6459 xmlXPathObjectPtr cur, newobj;
6460 xmlChar *tmp;
6461
6462 if (nargs < 2) {
6463 CHECK_ARITY(2);
6464 }
6465
6466 CAST_TO_STRING;
6467 cur = valuePop(ctxt);
6468 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6469 xmlXPathFreeObject(cur);
6470 return;
6471 }
6472 nargs--;
6473
6474 while (nargs > 0) {
6475 CAST_TO_STRING;
6476 newobj = valuePop(ctxt);
6477 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6478 xmlXPathFreeObject(newobj);
6479 xmlXPathFreeObject(cur);
6480 XP_ERROR(XPATH_INVALID_TYPE);
6481 }
6482 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6483 newobj->stringval = cur->stringval;
6484 cur->stringval = tmp;
6485
6486 xmlXPathFreeObject(newobj);
6487 nargs--;
6488 }
6489 valuePush(ctxt, cur);
6490}
6491
6492/**
6493 * xmlXPathContainsFunction:
6494 * @ctxt: the XPath Parser context
6495 * @nargs: the number of arguments
6496 *
6497 * Implement the contains() XPath function
6498 * boolean contains(string, string)
6499 * The contains function returns true if the first argument string
6500 * contains the second argument string, and otherwise returns false.
6501 */
6502void
6503xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6504 xmlXPathObjectPtr hay, needle;
6505
6506 CHECK_ARITY(2);
6507 CAST_TO_STRING;
6508 CHECK_TYPE(XPATH_STRING);
6509 needle = valuePop(ctxt);
6510 CAST_TO_STRING;
6511 hay = valuePop(ctxt);
6512 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6513 xmlXPathFreeObject(hay);
6514 xmlXPathFreeObject(needle);
6515 XP_ERROR(XPATH_INVALID_TYPE);
6516 }
6517 if (xmlStrstr(hay->stringval, needle->stringval))
6518 valuePush(ctxt, xmlXPathNewBoolean(1));
6519 else
6520 valuePush(ctxt, xmlXPathNewBoolean(0));
6521 xmlXPathFreeObject(hay);
6522 xmlXPathFreeObject(needle);
6523}
6524
6525/**
6526 * xmlXPathStartsWithFunction:
6527 * @ctxt: the XPath Parser context
6528 * @nargs: the number of arguments
6529 *
6530 * Implement the starts-with() XPath function
6531 * boolean starts-with(string, string)
6532 * The starts-with function returns true if the first argument string
6533 * starts with the second argument string, and otherwise returns false.
6534 */
6535void
6536xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6537 xmlXPathObjectPtr hay, needle;
6538 int n;
6539
6540 CHECK_ARITY(2);
6541 CAST_TO_STRING;
6542 CHECK_TYPE(XPATH_STRING);
6543 needle = valuePop(ctxt);
6544 CAST_TO_STRING;
6545 hay = valuePop(ctxt);
6546 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6547 xmlXPathFreeObject(hay);
6548 xmlXPathFreeObject(needle);
6549 XP_ERROR(XPATH_INVALID_TYPE);
6550 }
6551 n = xmlStrlen(needle->stringval);
6552 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6553 valuePush(ctxt, xmlXPathNewBoolean(0));
6554 else
6555 valuePush(ctxt, xmlXPathNewBoolean(1));
6556 xmlXPathFreeObject(hay);
6557 xmlXPathFreeObject(needle);
6558}
6559
6560/**
6561 * xmlXPathSubstringFunction:
6562 * @ctxt: the XPath Parser context
6563 * @nargs: the number of arguments
6564 *
6565 * Implement the substring() XPath function
6566 * string substring(string, number, number?)
6567 * The substring function returns the substring of the first argument
6568 * starting at the position specified in the second argument with
6569 * length specified in the third argument. For example,
6570 * substring("12345",2,3) returns "234". If the third argument is not
6571 * specified, it returns the substring starting at the position specified
6572 * in the second argument and continuing to the end of the string. For
6573 * example, substring("12345",2) returns "2345". More precisely, each
6574 * character in the string (see [3.6 Strings]) is considered to have a
6575 * numeric position: the position of the first character is 1, the position
6576 * of the second character is 2 and so on. The returned substring contains
6577 * those characters for which the position of the character is greater than
6578 * or equal to the second argument and, if the third argument is specified,
6579 * less than the sum of the second and third arguments; the comparisons
6580 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6581 * - substring("12345", 1.5, 2.6) returns "234"
6582 * - substring("12345", 0, 3) returns "12"
6583 * - substring("12345", 0 div 0, 3) returns ""
6584 * - substring("12345", 1, 0 div 0) returns ""
6585 * - substring("12345", -42, 1 div 0) returns "12345"
6586 * - substring("12345", -1 div 0, 1 div 0) returns ""
6587 */
6588void
6589xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6590 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006591 double le=0, in;
6592 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006593 xmlChar *ret;
6594
Owen Taylor3473f882001-02-23 17:55:21 +00006595 if (nargs < 2) {
6596 CHECK_ARITY(2);
6597 }
6598 if (nargs > 3) {
6599 CHECK_ARITY(3);
6600 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006601 /*
6602 * take care of possible last (position) argument
6603 */
Owen Taylor3473f882001-02-23 17:55:21 +00006604 if (nargs == 3) {
6605 CAST_TO_NUMBER;
6606 CHECK_TYPE(XPATH_NUMBER);
6607 len = valuePop(ctxt);
6608 le = len->floatval;
6609 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006610 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006611
Owen Taylor3473f882001-02-23 17:55:21 +00006612 CAST_TO_NUMBER;
6613 CHECK_TYPE(XPATH_NUMBER);
6614 start = valuePop(ctxt);
6615 in = start->floatval;
6616 xmlXPathFreeObject(start);
6617 CAST_TO_STRING;
6618 CHECK_TYPE(XPATH_STRING);
6619 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006620 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006621
Daniel Veillard97ac1312001-05-30 19:14:17 +00006622 /*
6623 * If last pos not present, calculate last position
6624 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006625 if (nargs != 3) {
6626 le = (double)m;
6627 if (in < 1.0)
6628 in = 1.0;
6629 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006630
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006631 /* Need to check for the special cases where either
6632 * the index is NaN, the length is NaN, or both
6633 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006634 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006635 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006636 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006637 * To meet the requirements of the spec, the arguments
6638 * must be converted to integer format before
6639 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006640 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006641 * First we go to integer form, rounding up
6642 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006643 */
6644 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006645 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006646
Daniel Veillard9e412302002-06-10 15:59:44 +00006647 if (xmlXPathIsInf(le) == 1) {
6648 l = m;
6649 if (i < 1)
6650 i = 1;
6651 }
6652 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6653 l = 0;
6654 else {
6655 l = (int) le;
6656 if (((double)l)+0.5 <= le) l++;
6657 }
6658
6659 /* Now we normalize inidices */
6660 i -= 1;
6661 l += i;
6662 if (i < 0)
6663 i = 0;
6664 if (l > m)
6665 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006666
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006667 /* number of chars to copy */
6668 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006669
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006670 ret = xmlUTF8Strsub(str->stringval, i, l);
6671 }
6672 else {
6673 ret = NULL;
6674 }
6675
Owen Taylor3473f882001-02-23 17:55:21 +00006676 if (ret == NULL)
6677 valuePush(ctxt, xmlXPathNewCString(""));
6678 else {
6679 valuePush(ctxt, xmlXPathNewString(ret));
6680 xmlFree(ret);
6681 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006682
Owen Taylor3473f882001-02-23 17:55:21 +00006683 xmlXPathFreeObject(str);
6684}
6685
6686/**
6687 * xmlXPathSubstringBeforeFunction:
6688 * @ctxt: the XPath Parser context
6689 * @nargs: the number of arguments
6690 *
6691 * Implement the substring-before() XPath function
6692 * string substring-before(string, string)
6693 * The substring-before function returns the substring of the first
6694 * argument string that precedes the first occurrence of the second
6695 * argument string in the first argument string, or the empty string
6696 * if the first argument string does not contain the second argument
6697 * string. For example, substring-before("1999/04/01","/") returns 1999.
6698 */
6699void
6700xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6701 xmlXPathObjectPtr str;
6702 xmlXPathObjectPtr find;
6703 xmlBufferPtr target;
6704 const xmlChar *point;
6705 int offset;
6706
6707 CHECK_ARITY(2);
6708 CAST_TO_STRING;
6709 find = valuePop(ctxt);
6710 CAST_TO_STRING;
6711 str = valuePop(ctxt);
6712
6713 target = xmlBufferCreate();
6714 if (target) {
6715 point = xmlStrstr(str->stringval, find->stringval);
6716 if (point) {
6717 offset = (int)(point - str->stringval);
6718 xmlBufferAdd(target, str->stringval, offset);
6719 }
6720 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6721 xmlBufferFree(target);
6722 }
6723
6724 xmlXPathFreeObject(str);
6725 xmlXPathFreeObject(find);
6726}
6727
6728/**
6729 * xmlXPathSubstringAfterFunction:
6730 * @ctxt: the XPath Parser context
6731 * @nargs: the number of arguments
6732 *
6733 * Implement the substring-after() XPath function
6734 * string substring-after(string, string)
6735 * The substring-after function returns the substring of the first
6736 * argument string that follows the first occurrence of the second
6737 * argument string in the first argument string, or the empty stringi
6738 * if the first argument string does not contain the second argument
6739 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6740 * and substring-after("1999/04/01","19") returns 99/04/01.
6741 */
6742void
6743xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6744 xmlXPathObjectPtr str;
6745 xmlXPathObjectPtr find;
6746 xmlBufferPtr target;
6747 const xmlChar *point;
6748 int offset;
6749
6750 CHECK_ARITY(2);
6751 CAST_TO_STRING;
6752 find = valuePop(ctxt);
6753 CAST_TO_STRING;
6754 str = valuePop(ctxt);
6755
6756 target = xmlBufferCreate();
6757 if (target) {
6758 point = xmlStrstr(str->stringval, find->stringval);
6759 if (point) {
6760 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6761 xmlBufferAdd(target, &str->stringval[offset],
6762 xmlStrlen(str->stringval) - offset);
6763 }
6764 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6765 xmlBufferFree(target);
6766 }
6767
6768 xmlXPathFreeObject(str);
6769 xmlXPathFreeObject(find);
6770}
6771
6772/**
6773 * xmlXPathNormalizeFunction:
6774 * @ctxt: the XPath Parser context
6775 * @nargs: the number of arguments
6776 *
6777 * Implement the normalize-space() XPath function
6778 * string normalize-space(string?)
6779 * The normalize-space function returns the argument string with white
6780 * space normalized by stripping leading and trailing whitespace
6781 * and replacing sequences of whitespace characters by a single
6782 * space. Whitespace characters are the same allowed by the S production
6783 * in XML. If the argument is omitted, it defaults to the context
6784 * node converted to a string, in other words the value of the context node.
6785 */
6786void
6787xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6788 xmlXPathObjectPtr obj = NULL;
6789 xmlChar *source = NULL;
6790 xmlBufferPtr target;
6791 xmlChar blank;
6792
6793 if (nargs == 0) {
6794 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006795 valuePush(ctxt,
6796 xmlXPathWrapString(
6797 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006798 nargs = 1;
6799 }
6800
6801 CHECK_ARITY(1);
6802 CAST_TO_STRING;
6803 CHECK_TYPE(XPATH_STRING);
6804 obj = valuePop(ctxt);
6805 source = obj->stringval;
6806
6807 target = xmlBufferCreate();
6808 if (target && source) {
6809
6810 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006811 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006812 source++;
6813
6814 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6815 blank = 0;
6816 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006817 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006818 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006819 } else {
6820 if (blank) {
6821 xmlBufferAdd(target, &blank, 1);
6822 blank = 0;
6823 }
6824 xmlBufferAdd(target, source, 1);
6825 }
6826 source++;
6827 }
6828
6829 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6830 xmlBufferFree(target);
6831 }
6832 xmlXPathFreeObject(obj);
6833}
6834
6835/**
6836 * xmlXPathTranslateFunction:
6837 * @ctxt: the XPath Parser context
6838 * @nargs: the number of arguments
6839 *
6840 * Implement the translate() XPath function
6841 * string translate(string, string, string)
6842 * The translate function returns the first argument string with
6843 * occurrences of characters in the second argument string replaced
6844 * by the character at the corresponding position in the third argument
6845 * string. For example, translate("bar","abc","ABC") returns the string
6846 * BAr. If there is a character in the second argument string with no
6847 * character at a corresponding position in the third argument string
6848 * (because the second argument string is longer than the third argument
6849 * string), then occurrences of that character in the first argument
6850 * string are removed. For example, translate("--aaa--","abc-","ABC")
6851 * returns "AAA". If a character occurs more than once in second
6852 * argument string, then the first occurrence determines the replacement
6853 * character. If the third argument string is longer than the second
6854 * argument string, then excess characters are ignored.
6855 */
6856void
6857xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006858 xmlXPathObjectPtr str;
6859 xmlXPathObjectPtr from;
6860 xmlXPathObjectPtr to;
6861 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006862 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006863 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006864 xmlChar *point;
6865 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006866
Daniel Veillarde043ee12001-04-16 14:08:07 +00006867 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006868
Daniel Veillarde043ee12001-04-16 14:08:07 +00006869 CAST_TO_STRING;
6870 to = valuePop(ctxt);
6871 CAST_TO_STRING;
6872 from = valuePop(ctxt);
6873 CAST_TO_STRING;
6874 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006875
Daniel Veillarde043ee12001-04-16 14:08:07 +00006876 target = xmlBufferCreate();
6877 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006878 max = xmlUTF8Strlen(to->stringval);
6879 for (cptr = str->stringval; (ch=*cptr); ) {
6880 offset = xmlUTF8Strloc(from->stringval, cptr);
6881 if (offset >= 0) {
6882 if (offset < max) {
6883 point = xmlUTF8Strpos(to->stringval, offset);
6884 if (point)
6885 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6886 }
6887 } else
6888 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6889
6890 /* Step to next character in input */
6891 cptr++;
6892 if ( ch & 0x80 ) {
6893 /* if not simple ascii, verify proper format */
6894 if ( (ch & 0xc0) != 0xc0 ) {
6895 xmlGenericError(xmlGenericErrorContext,
6896 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6897 break;
6898 }
6899 /* then skip over remaining bytes for this char */
6900 while ( (ch <<= 1) & 0x80 )
6901 if ( (*cptr++ & 0xc0) != 0x80 ) {
6902 xmlGenericError(xmlGenericErrorContext,
6903 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6904 break;
6905 }
6906 if (ch & 0x80) /* must have had error encountered */
6907 break;
6908 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006909 }
Owen Taylor3473f882001-02-23 17:55:21 +00006910 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006911 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6912 xmlBufferFree(target);
6913 xmlXPathFreeObject(str);
6914 xmlXPathFreeObject(from);
6915 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006916}
6917
6918/**
6919 * xmlXPathBooleanFunction:
6920 * @ctxt: the XPath Parser context
6921 * @nargs: the number of arguments
6922 *
6923 * Implement the boolean() XPath function
6924 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00006925 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006926 * - a number is true if and only if it is neither positive or
6927 * negative zero nor NaN
6928 * - a node-set is true if and only if it is non-empty
6929 * - a string is true if and only if its length is non-zero
6930 */
6931void
6932xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6933 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006934
6935 CHECK_ARITY(1);
6936 cur = valuePop(ctxt);
6937 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006938 cur = xmlXPathConvertBoolean(cur);
6939 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006940}
6941
6942/**
6943 * xmlXPathNotFunction:
6944 * @ctxt: the XPath Parser context
6945 * @nargs: the number of arguments
6946 *
6947 * Implement the not() XPath function
6948 * boolean not(boolean)
6949 * The not function returns true if its argument is false,
6950 * and false otherwise.
6951 */
6952void
6953xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6954 CHECK_ARITY(1);
6955 CAST_TO_BOOLEAN;
6956 CHECK_TYPE(XPATH_BOOLEAN);
6957 ctxt->value->boolval = ! ctxt->value->boolval;
6958}
6959
6960/**
6961 * xmlXPathTrueFunction:
6962 * @ctxt: the XPath Parser context
6963 * @nargs: the number of arguments
6964 *
6965 * Implement the true() XPath function
6966 * boolean true()
6967 */
6968void
6969xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6970 CHECK_ARITY(0);
6971 valuePush(ctxt, xmlXPathNewBoolean(1));
6972}
6973
6974/**
6975 * xmlXPathFalseFunction:
6976 * @ctxt: the XPath Parser context
6977 * @nargs: the number of arguments
6978 *
6979 * Implement the false() XPath function
6980 * boolean false()
6981 */
6982void
6983xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6984 CHECK_ARITY(0);
6985 valuePush(ctxt, xmlXPathNewBoolean(0));
6986}
6987
6988/**
6989 * xmlXPathLangFunction:
6990 * @ctxt: the XPath Parser context
6991 * @nargs: the number of arguments
6992 *
6993 * Implement the lang() XPath function
6994 * boolean lang(string)
6995 * The lang function returns true or false depending on whether the
6996 * language of the context node as specified by xml:lang attributes
6997 * is the same as or is a sublanguage of the language specified by
6998 * the argument string. The language of the context node is determined
6999 * by the value of the xml:lang attribute on the context node, or, if
7000 * the context node has no xml:lang attribute, by the value of the
7001 * xml:lang attribute on the nearest ancestor of the context node that
7002 * has an xml:lang attribute. If there is no such attribute, then lang
7003 * returns false. If there is such an attribute, then lang returns
7004 * true if the attribute value is equal to the argument ignoring case,
7005 * or if there is some suffix starting with - such that the attribute
7006 * value is equal to the argument ignoring that suffix of the attribute
7007 * value and ignoring case.
7008 */
7009void
7010xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7011 xmlXPathObjectPtr val;
7012 const xmlChar *theLang;
7013 const xmlChar *lang;
7014 int ret = 0;
7015 int i;
7016
7017 CHECK_ARITY(1);
7018 CAST_TO_STRING;
7019 CHECK_TYPE(XPATH_STRING);
7020 val = valuePop(ctxt);
7021 lang = val->stringval;
7022 theLang = xmlNodeGetLang(ctxt->context->node);
7023 if ((theLang != NULL) && (lang != NULL)) {
7024 for (i = 0;lang[i] != 0;i++)
7025 if (toupper(lang[i]) != toupper(theLang[i]))
7026 goto not_equal;
7027 ret = 1;
7028 }
7029not_equal:
William M. Bracka59ddb52004-02-25 08:12:32 +00007030 xmlFree((void *)theLang);
Owen Taylor3473f882001-02-23 17:55:21 +00007031 xmlXPathFreeObject(val);
7032 valuePush(ctxt, xmlXPathNewBoolean(ret));
7033}
7034
7035/**
7036 * xmlXPathNumberFunction:
7037 * @ctxt: the XPath Parser context
7038 * @nargs: the number of arguments
7039 *
7040 * Implement the number() XPath function
7041 * number number(object?)
7042 */
7043void
7044xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7045 xmlXPathObjectPtr cur;
7046 double res;
7047
7048 if (nargs == 0) {
7049 if (ctxt->context->node == NULL) {
7050 valuePush(ctxt, xmlXPathNewFloat(0.0));
7051 } else {
7052 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7053
7054 res = xmlXPathStringEvalNumber(content);
7055 valuePush(ctxt, xmlXPathNewFloat(res));
7056 xmlFree(content);
7057 }
7058 return;
7059 }
7060
7061 CHECK_ARITY(1);
7062 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007063 cur = xmlXPathConvertNumber(cur);
7064 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007065}
7066
7067/**
7068 * xmlXPathSumFunction:
7069 * @ctxt: the XPath Parser context
7070 * @nargs: the number of arguments
7071 *
7072 * Implement the sum() XPath function
7073 * number sum(node-set)
7074 * The sum function returns the sum of the values of the nodes in
7075 * the argument node-set.
7076 */
7077void
7078xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7079 xmlXPathObjectPtr cur;
7080 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007081 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007082
7083 CHECK_ARITY(1);
7084 if ((ctxt->value == NULL) ||
7085 ((ctxt->value->type != XPATH_NODESET) &&
7086 (ctxt->value->type != XPATH_XSLT_TREE)))
7087 XP_ERROR(XPATH_INVALID_TYPE);
7088 cur = valuePop(ctxt);
7089
William M. Brack08171912003-12-29 02:52:11 +00007090 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007091 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7092 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007093 }
7094 }
William M. Brack08171912003-12-29 02:52:11 +00007095 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007096 xmlXPathFreeObject(cur);
7097}
7098
7099/**
7100 * xmlXPathFloorFunction:
7101 * @ctxt: the XPath Parser context
7102 * @nargs: the number of arguments
7103 *
7104 * Implement the floor() XPath function
7105 * number floor(number)
7106 * The floor function returns the largest (closest to positive infinity)
7107 * number that is not greater than the argument and that is an integer.
7108 */
7109void
7110xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007111 double f;
7112
Owen Taylor3473f882001-02-23 17:55:21 +00007113 CHECK_ARITY(1);
7114 CAST_TO_NUMBER;
7115 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007116
7117 f = (double)((int) ctxt->value->floatval);
7118 if (f != ctxt->value->floatval) {
7119 if (ctxt->value->floatval > 0)
7120 ctxt->value->floatval = f;
7121 else
7122 ctxt->value->floatval = f - 1;
7123 }
Owen Taylor3473f882001-02-23 17:55:21 +00007124}
7125
7126/**
7127 * xmlXPathCeilingFunction:
7128 * @ctxt: the XPath Parser context
7129 * @nargs: the number of arguments
7130 *
7131 * Implement the ceiling() XPath function
7132 * number ceiling(number)
7133 * The ceiling function returns the smallest (closest to negative infinity)
7134 * number that is not less than the argument and that is an integer.
7135 */
7136void
7137xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7138 double f;
7139
7140 CHECK_ARITY(1);
7141 CAST_TO_NUMBER;
7142 CHECK_TYPE(XPATH_NUMBER);
7143
7144#if 0
7145 ctxt->value->floatval = ceil(ctxt->value->floatval);
7146#else
7147 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007148 if (f != ctxt->value->floatval) {
7149 if (ctxt->value->floatval > 0)
7150 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007151 else {
7152 if (ctxt->value->floatval < 0 && f == 0)
7153 ctxt->value->floatval = xmlXPathNZERO;
7154 else
7155 ctxt->value->floatval = f;
7156 }
7157
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007158 }
Owen Taylor3473f882001-02-23 17:55:21 +00007159#endif
7160}
7161
7162/**
7163 * xmlXPathRoundFunction:
7164 * @ctxt: the XPath Parser context
7165 * @nargs: the number of arguments
7166 *
7167 * Implement the round() XPath function
7168 * number round(number)
7169 * The round function returns the number that is closest to the
7170 * argument and that is an integer. If there are two such numbers,
7171 * then the one that is even is returned.
7172 */
7173void
7174xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7175 double f;
7176
7177 CHECK_ARITY(1);
7178 CAST_TO_NUMBER;
7179 CHECK_TYPE(XPATH_NUMBER);
7180
Daniel Veillardcda96922001-08-21 10:56:31 +00007181 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7182 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7183 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007184 (ctxt->value->floatval == 0.0))
7185 return;
7186
Owen Taylor3473f882001-02-23 17:55:21 +00007187 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007188 if (ctxt->value->floatval < 0) {
7189 if (ctxt->value->floatval < f - 0.5)
7190 ctxt->value->floatval = f - 1;
7191 else
7192 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007193 if (ctxt->value->floatval == 0)
7194 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007195 } else {
7196 if (ctxt->value->floatval < f + 0.5)
7197 ctxt->value->floatval = f;
7198 else
7199 ctxt->value->floatval = f + 1;
7200 }
Owen Taylor3473f882001-02-23 17:55:21 +00007201}
7202
7203/************************************************************************
7204 * *
7205 * The Parser *
7206 * *
7207 ************************************************************************/
7208
7209/*
William M. Brack08171912003-12-29 02:52:11 +00007210 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007211 * implementation.
7212 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007213static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007214static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007215static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007216static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007217static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7218 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007219
7220/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007221 * xmlXPathCurrentChar:
7222 * @ctxt: the XPath parser context
7223 * @cur: pointer to the beginning of the char
7224 * @len: pointer to the length of the char read
7225 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007226 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007227 * bytes in the input buffer.
7228 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007229 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007230 */
7231
7232static int
7233xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7234 unsigned char c;
7235 unsigned int val;
7236 const xmlChar *cur;
7237
7238 if (ctxt == NULL)
7239 return(0);
7240 cur = ctxt->cur;
7241
7242 /*
7243 * We are supposed to handle UTF8, check it's valid
7244 * From rfc2044: encoding of the Unicode values on UTF-8:
7245 *
7246 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7247 * 0000 0000-0000 007F 0xxxxxxx
7248 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7249 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7250 *
7251 * Check for the 0x110000 limit too
7252 */
7253 c = *cur;
7254 if (c & 0x80) {
7255 if ((cur[1] & 0xc0) != 0x80)
7256 goto encoding_error;
7257 if ((c & 0xe0) == 0xe0) {
7258
7259 if ((cur[2] & 0xc0) != 0x80)
7260 goto encoding_error;
7261 if ((c & 0xf0) == 0xf0) {
7262 if (((c & 0xf8) != 0xf0) ||
7263 ((cur[3] & 0xc0) != 0x80))
7264 goto encoding_error;
7265 /* 4-byte code */
7266 *len = 4;
7267 val = (cur[0] & 0x7) << 18;
7268 val |= (cur[1] & 0x3f) << 12;
7269 val |= (cur[2] & 0x3f) << 6;
7270 val |= cur[3] & 0x3f;
7271 } else {
7272 /* 3-byte code */
7273 *len = 3;
7274 val = (cur[0] & 0xf) << 12;
7275 val |= (cur[1] & 0x3f) << 6;
7276 val |= cur[2] & 0x3f;
7277 }
7278 } else {
7279 /* 2-byte code */
7280 *len = 2;
7281 val = (cur[0] & 0x1f) << 6;
7282 val |= cur[1] & 0x3f;
7283 }
7284 if (!IS_CHAR(val)) {
7285 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7286 }
7287 return(val);
7288 } else {
7289 /* 1-byte code */
7290 *len = 1;
7291 return((int) *cur);
7292 }
7293encoding_error:
7294 /*
William M. Brack08171912003-12-29 02:52:11 +00007295 * If we detect an UTF8 error that probably means that the
7296 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007297 * declaration header. Report the error and switch the encoding
7298 * to ISO-Latin-1 (if you don't like this policy, just declare the
7299 * encoding !)
7300 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007301 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007302 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007303}
7304
7305/**
Owen Taylor3473f882001-02-23 17:55:21 +00007306 * xmlXPathParseNCName:
7307 * @ctxt: the XPath Parser context
7308 *
7309 * parse an XML namespace non qualified name.
7310 *
7311 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7312 *
7313 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7314 * CombiningChar | Extender
7315 *
7316 * Returns the namespace name or NULL
7317 */
7318
7319xmlChar *
7320xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007321 const xmlChar *in;
7322 xmlChar *ret;
7323 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007324
Daniel Veillard2156a562001-04-28 12:24:34 +00007325 /*
7326 * Accelerator for simple ASCII names
7327 */
7328 in = ctxt->cur;
7329 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7330 ((*in >= 0x41) && (*in <= 0x5A)) ||
7331 (*in == '_')) {
7332 in++;
7333 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7334 ((*in >= 0x41) && (*in <= 0x5A)) ||
7335 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007336 (*in == '_') || (*in == '.') ||
7337 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007338 in++;
7339 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7340 (*in == '[') || (*in == ']') || (*in == ':') ||
7341 (*in == '@') || (*in == '*')) {
7342 count = in - ctxt->cur;
7343 if (count == 0)
7344 return(NULL);
7345 ret = xmlStrndup(ctxt->cur, count);
7346 ctxt->cur = in;
7347 return(ret);
7348 }
7349 }
7350 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007351}
7352
Daniel Veillard2156a562001-04-28 12:24:34 +00007353
Owen Taylor3473f882001-02-23 17:55:21 +00007354/**
7355 * xmlXPathParseQName:
7356 * @ctxt: the XPath Parser context
7357 * @prefix: a xmlChar **
7358 *
7359 * parse an XML qualified name
7360 *
7361 * [NS 5] QName ::= (Prefix ':')? LocalPart
7362 *
7363 * [NS 6] Prefix ::= NCName
7364 *
7365 * [NS 7] LocalPart ::= NCName
7366 *
7367 * Returns the function returns the local part, and prefix is updated
7368 * to get the Prefix if any.
7369 */
7370
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007371static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007372xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7373 xmlChar *ret = NULL;
7374
7375 *prefix = NULL;
7376 ret = xmlXPathParseNCName(ctxt);
7377 if (CUR == ':') {
7378 *prefix = ret;
7379 NEXT;
7380 ret = xmlXPathParseNCName(ctxt);
7381 }
7382 return(ret);
7383}
7384
7385/**
7386 * xmlXPathParseName:
7387 * @ctxt: the XPath Parser context
7388 *
7389 * parse an XML name
7390 *
7391 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7392 * CombiningChar | Extender
7393 *
7394 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7395 *
7396 * Returns the namespace name or NULL
7397 */
7398
7399xmlChar *
7400xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007401 const xmlChar *in;
7402 xmlChar *ret;
7403 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007404
Daniel Veillard61d80a22001-04-27 17:13:01 +00007405 /*
7406 * Accelerator for simple ASCII names
7407 */
7408 in = ctxt->cur;
7409 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7410 ((*in >= 0x41) && (*in <= 0x5A)) ||
7411 (*in == '_') || (*in == ':')) {
7412 in++;
7413 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7414 ((*in >= 0x41) && (*in <= 0x5A)) ||
7415 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007416 (*in == '_') || (*in == '-') ||
7417 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007418 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007419 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007420 count = in - ctxt->cur;
7421 ret = xmlStrndup(ctxt->cur, count);
7422 ctxt->cur = in;
7423 return(ret);
7424 }
7425 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007426 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007427}
7428
Daniel Veillard61d80a22001-04-27 17:13:01 +00007429static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007430xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007431 xmlChar buf[XML_MAX_NAMELEN + 5];
7432 int len = 0, l;
7433 int c;
7434
7435 /*
7436 * Handler for more complex cases
7437 */
7438 c = CUR_CHAR(l);
7439 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007440 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7441 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007442 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007443 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007444 return(NULL);
7445 }
7446
7447 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7448 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7449 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007450 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007451 (IS_COMBINING(c)) ||
7452 (IS_EXTENDER(c)))) {
7453 COPY_BUF(l,buf,len,c);
7454 NEXTL(l);
7455 c = CUR_CHAR(l);
7456 if (len >= XML_MAX_NAMELEN) {
7457 /*
7458 * Okay someone managed to make a huge name, so he's ready to pay
7459 * for the processing speed.
7460 */
7461 xmlChar *buffer;
7462 int max = len * 2;
7463
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007464 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007465 if (buffer == NULL) {
7466 XP_ERROR0(XPATH_MEMORY_ERROR);
7467 }
7468 memcpy(buffer, buf, len);
7469 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7470 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007471 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007472 (IS_COMBINING(c)) ||
7473 (IS_EXTENDER(c))) {
7474 if (len + 10 > max) {
7475 max *= 2;
7476 buffer = (xmlChar *) xmlRealloc(buffer,
7477 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007478 if (buffer == NULL) {
7479 XP_ERROR0(XPATH_MEMORY_ERROR);
7480 }
7481 }
7482 COPY_BUF(l,buffer,len,c);
7483 NEXTL(l);
7484 c = CUR_CHAR(l);
7485 }
7486 buffer[len] = 0;
7487 return(buffer);
7488 }
7489 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007490 if (len == 0)
7491 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007492 return(xmlStrndup(buf, len));
7493}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007494
7495#define MAX_FRAC 20
7496
William M. Brack372a4452004-02-17 13:09:23 +00007497/*
7498 * These are used as divisors for the fractional part of a number.
7499 * Since the table includes 1.0 (representing '0' fractional digits),
7500 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
7501 */
7502static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007503 1.0, 10.0, 100.0, 1000.0, 10000.0,
7504 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7505 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7506 100000000000000.0,
7507 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00007508 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00007509};
7510
Owen Taylor3473f882001-02-23 17:55:21 +00007511/**
7512 * xmlXPathStringEvalNumber:
7513 * @str: A string to scan
7514 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007515 * [30a] Float ::= Number ('e' Digits?)?
7516 *
Owen Taylor3473f882001-02-23 17:55:21 +00007517 * [30] Number ::= Digits ('.' Digits?)?
7518 * | '.' Digits
7519 * [31] Digits ::= [0-9]+
7520 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007521 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007522 * In complement of the Number expression, this function also handles
7523 * negative values : '-' Number.
7524 *
7525 * Returns the double value.
7526 */
7527double
7528xmlXPathStringEvalNumber(const xmlChar *str) {
7529 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007530 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007531 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007532 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007533 int exponent = 0;
7534 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007535#ifdef __GNUC__
7536 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007537 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007538#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007539 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007540 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007541 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7542 return(xmlXPathNAN);
7543 }
7544 if (*cur == '-') {
7545 isneg = 1;
7546 cur++;
7547 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007548
7549#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007550 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007551 * tmp/temp is a workaround against a gcc compiler bug
7552 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007553 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007554 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007555 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007556 ret = ret * 10;
7557 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007558 ok = 1;
7559 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007560 temp = (double) tmp;
7561 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007562 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007563#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007564 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007565 while ((*cur >= '0') && (*cur <= '9')) {
7566 ret = ret * 10 + (*cur - '0');
7567 ok = 1;
7568 cur++;
7569 }
7570#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007571
Owen Taylor3473f882001-02-23 17:55:21 +00007572 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007573 int v, frac = 0;
7574 double fraction = 0;
7575
Owen Taylor3473f882001-02-23 17:55:21 +00007576 cur++;
7577 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7578 return(xmlXPathNAN);
7579 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007580 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7581 v = (*cur - '0');
7582 fraction = fraction * 10 + v;
7583 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007584 cur++;
7585 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007586 fraction /= my_pow10[frac];
7587 ret = ret + fraction;
7588 while ((*cur >= '0') && (*cur <= '9'))
7589 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007590 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007591 if ((*cur == 'e') || (*cur == 'E')) {
7592 cur++;
7593 if (*cur == '-') {
7594 is_exponent_negative = 1;
7595 cur++;
William M. Brack99127052004-05-24 02:52:28 +00007596 } else if (*cur == '+') {
7597 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007598 }
7599 while ((*cur >= '0') && (*cur <= '9')) {
7600 exponent = exponent * 10 + (*cur - '0');
7601 cur++;
7602 }
7603 }
William M. Brack76e95df2003-10-18 16:20:14 +00007604 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007605 if (*cur != 0) return(xmlXPathNAN);
7606 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007607 if (is_exponent_negative) exponent = -exponent;
7608 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007609 return(ret);
7610}
7611
7612/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007613 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007614 * @ctxt: the XPath Parser context
7615 *
7616 * [30] Number ::= Digits ('.' Digits?)?
7617 * | '.' Digits
7618 * [31] Digits ::= [0-9]+
7619 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007620 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007621 *
7622 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007623static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007624xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7625{
Owen Taylor3473f882001-02-23 17:55:21 +00007626 double ret = 0.0;
7627 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007628 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007629 int exponent = 0;
7630 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007631#ifdef __GNUC__
7632 unsigned long tmp = 0;
7633 double temp;
7634#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007635
7636 CHECK_ERROR;
7637 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7638 XP_ERROR(XPATH_NUMBER_ERROR);
7639 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007640#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007641 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007642 * tmp/temp is a workaround against a gcc compiler bug
7643 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007644 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007645 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007646 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007647 ret = ret * 10;
7648 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007649 ok = 1;
7650 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007651 temp = (double) tmp;
7652 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007653 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007654#else
7655 ret = 0;
7656 while ((CUR >= '0') && (CUR <= '9')) {
7657 ret = ret * 10 + (CUR - '0');
7658 ok = 1;
7659 NEXT;
7660 }
7661#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007662 if (CUR == '.') {
7663 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007664 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7665 XP_ERROR(XPATH_NUMBER_ERROR);
7666 }
7667 while ((CUR >= '0') && (CUR <= '9')) {
7668 mult /= 10;
7669 ret = ret + (CUR - '0') * mult;
7670 NEXT;
7671 }
Owen Taylor3473f882001-02-23 17:55:21 +00007672 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007673 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007674 NEXT;
7675 if (CUR == '-') {
7676 is_exponent_negative = 1;
7677 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00007678 } else if (CUR == '+') {
7679 NEXT;
7680 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007681 while ((CUR >= '0') && (CUR <= '9')) {
7682 exponent = exponent * 10 + (CUR - '0');
7683 NEXT;
7684 }
7685 if (is_exponent_negative)
7686 exponent = -exponent;
7687 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007688 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007689 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007690 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007691}
7692
7693/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007694 * xmlXPathParseLiteral:
7695 * @ctxt: the XPath Parser context
7696 *
7697 * Parse a Literal
7698 *
7699 * [29] Literal ::= '"' [^"]* '"'
7700 * | "'" [^']* "'"
7701 *
7702 * Returns the value found or NULL in case of error
7703 */
7704static xmlChar *
7705xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7706 const xmlChar *q;
7707 xmlChar *ret = NULL;
7708
7709 if (CUR == '"') {
7710 NEXT;
7711 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007712 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007713 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007714 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007715 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7716 } else {
7717 ret = xmlStrndup(q, CUR_PTR - q);
7718 NEXT;
7719 }
7720 } else if (CUR == '\'') {
7721 NEXT;
7722 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007723 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007724 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007725 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007726 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7727 } else {
7728 ret = xmlStrndup(q, CUR_PTR - q);
7729 NEXT;
7730 }
7731 } else {
7732 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7733 }
7734 return(ret);
7735}
7736
7737/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007738 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007739 * @ctxt: the XPath Parser context
7740 *
7741 * Parse a Literal and push it on the stack.
7742 *
7743 * [29] Literal ::= '"' [^"]* '"'
7744 * | "'" [^']* "'"
7745 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007746 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007747 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007748static void
7749xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007750 const xmlChar *q;
7751 xmlChar *ret = NULL;
7752
7753 if (CUR == '"') {
7754 NEXT;
7755 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007756 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007757 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007758 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007759 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7760 } else {
7761 ret = xmlStrndup(q, CUR_PTR - q);
7762 NEXT;
7763 }
7764 } else if (CUR == '\'') {
7765 NEXT;
7766 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007767 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007768 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007769 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007770 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7771 } else {
7772 ret = xmlStrndup(q, CUR_PTR - q);
7773 NEXT;
7774 }
7775 } else {
7776 XP_ERROR(XPATH_START_LITERAL_ERROR);
7777 }
7778 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007779 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7780 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007781 xmlFree(ret);
7782}
7783
7784/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007785 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007786 * @ctxt: the XPath Parser context
7787 *
7788 * Parse a VariableReference, evaluate it and push it on the stack.
7789 *
7790 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00007791 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00007792 * of any of the types that are possible for the value of an expression,
7793 * and may also be of additional types not specified here.
7794 *
7795 * Early evaluation is possible since:
7796 * The variable bindings [...] used to evaluate a subexpression are
7797 * always the same as those used to evaluate the containing expression.
7798 *
7799 * [36] VariableReference ::= '$' QName
7800 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007801static void
7802xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007803 xmlChar *name;
7804 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007805
7806 SKIP_BLANKS;
7807 if (CUR != '$') {
7808 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7809 }
7810 NEXT;
7811 name = xmlXPathParseQName(ctxt, &prefix);
7812 if (name == NULL) {
7813 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7814 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007815 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007816 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7817 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007818 SKIP_BLANKS;
7819}
7820
7821/**
7822 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007823 * @name: a name string
7824 *
7825 * Is the name given a NodeType one.
7826 *
7827 * [38] NodeType ::= 'comment'
7828 * | 'text'
7829 * | 'processing-instruction'
7830 * | 'node'
7831 *
7832 * Returns 1 if true 0 otherwise
7833 */
7834int
7835xmlXPathIsNodeType(const xmlChar *name) {
7836 if (name == NULL)
7837 return(0);
7838
Daniel Veillard1971ee22002-01-31 20:29:19 +00007839 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007840 return(1);
7841 if (xmlStrEqual(name, BAD_CAST "text"))
7842 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007843 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007844 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007845 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007846 return(1);
7847 return(0);
7848}
7849
7850/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007851 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007852 * @ctxt: the XPath Parser context
7853 *
7854 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7855 * [17] Argument ::= Expr
7856 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007857 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007858 * pushed on the stack
7859 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007860static void
7861xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007862 xmlChar *name;
7863 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007864 int nbargs = 0;
7865
7866 name = xmlXPathParseQName(ctxt, &prefix);
7867 if (name == NULL) {
7868 XP_ERROR(XPATH_EXPR_ERROR);
7869 }
7870 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007871#ifdef DEBUG_EXPR
7872 if (prefix == NULL)
7873 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7874 name);
7875 else
7876 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7877 prefix, name);
7878#endif
7879
Owen Taylor3473f882001-02-23 17:55:21 +00007880 if (CUR != '(') {
7881 XP_ERROR(XPATH_EXPR_ERROR);
7882 }
7883 NEXT;
7884 SKIP_BLANKS;
7885
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007886 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007887 if (CUR != ')') {
7888 while (CUR != 0) {
7889 int op1 = ctxt->comp->last;
7890 ctxt->comp->last = -1;
7891 xmlXPathCompileExpr(ctxt);
7892 CHECK_ERROR;
7893 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7894 nbargs++;
7895 if (CUR == ')') break;
7896 if (CUR != ',') {
7897 XP_ERROR(XPATH_EXPR_ERROR);
7898 }
7899 NEXT;
7900 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007901 }
Owen Taylor3473f882001-02-23 17:55:21 +00007902 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007903 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7904 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007905 NEXT;
7906 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007907}
7908
7909/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007910 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007911 * @ctxt: the XPath Parser context
7912 *
7913 * [15] PrimaryExpr ::= VariableReference
7914 * | '(' Expr ')'
7915 * | Literal
7916 * | Number
7917 * | FunctionCall
7918 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007919 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007920 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007921static void
7922xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007923 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007924 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007925 else if (CUR == '(') {
7926 NEXT;
7927 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007928 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007929 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007930 if (CUR != ')') {
7931 XP_ERROR(XPATH_EXPR_ERROR);
7932 }
7933 NEXT;
7934 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007935 } else if (IS_DIGIT_CH(CUR) || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007936 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007937 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007938 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007939 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007940 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007941 }
7942 SKIP_BLANKS;
7943}
7944
7945/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007946 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007947 * @ctxt: the XPath Parser context
7948 *
7949 * [20] FilterExpr ::= PrimaryExpr
7950 * | FilterExpr Predicate
7951 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007952 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007953 * Square brackets are used to filter expressions in the same way that
7954 * they are used in location paths. It is an error if the expression to
7955 * be filtered does not evaluate to a node-set. The context node list
7956 * used for evaluating the expression in square brackets is the node-set
7957 * to be filtered listed in document order.
7958 */
7959
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007960static void
7961xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7962 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007963 CHECK_ERROR;
7964 SKIP_BLANKS;
7965
7966 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007967 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007968 SKIP_BLANKS;
7969 }
7970
7971
7972}
7973
7974/**
7975 * xmlXPathScanName:
7976 * @ctxt: the XPath Parser context
7977 *
7978 * Trickery: parse an XML name but without consuming the input flow
7979 * Needed to avoid insanity in the parser state.
7980 *
7981 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7982 * CombiningChar | Extender
7983 *
7984 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7985 *
7986 * [6] Names ::= Name (S Name)*
7987 *
7988 * Returns the Name parsed or NULL
7989 */
7990
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007991static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007992xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7993 xmlChar buf[XML_MAX_NAMELEN];
7994 int len = 0;
7995
7996 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007997 if (!IS_LETTER_CH(CUR) && (CUR != '_') &&
Owen Taylor3473f882001-02-23 17:55:21 +00007998 (CUR != ':')) {
7999 return(NULL);
8000 }
8001
William M. Brack76e95df2003-10-18 16:20:14 +00008002 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008003 (NXT(len) == '.') || (NXT(len) == '-') ||
8004 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00008005 (IS_COMBINING_CH(NXT(len))) ||
8006 (IS_EXTENDER_CH(NXT(len)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008007 buf[len] = NXT(len);
8008 len++;
8009 if (len >= XML_MAX_NAMELEN) {
8010 xmlGenericError(xmlGenericErrorContext,
8011 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
William M. Brack76e95df2003-10-18 16:20:14 +00008012 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008013 (NXT(len) == '.') || (NXT(len) == '-') ||
8014 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00008015 (IS_COMBINING_CH(NXT(len))) ||
8016 (IS_EXTENDER_CH(NXT(len))))
Owen Taylor3473f882001-02-23 17:55:21 +00008017 len++;
8018 break;
8019 }
8020 }
8021 return(xmlStrndup(buf, len));
8022}
8023
8024/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008025 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008026 * @ctxt: the XPath Parser context
8027 *
8028 * [19] PathExpr ::= LocationPath
8029 * | FilterExpr
8030 * | FilterExpr '/' RelativeLocationPath
8031 * | FilterExpr '//' RelativeLocationPath
8032 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008033 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008034 * The / operator and // operators combine an arbitrary expression
8035 * and a relative location path. It is an error if the expression
8036 * does not evaluate to a node-set.
8037 * The / operator does composition in the same way as when / is
8038 * used in a location path. As in location paths, // is short for
8039 * /descendant-or-self::node()/.
8040 */
8041
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008042static void
8043xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008044 int lc = 1; /* Should we branch to LocationPath ? */
8045 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8046
8047 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00008048 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT_CH(CUR)) ||
8049 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008050 lc = 0;
8051 } else if (CUR == '*') {
8052 /* relative or absolute location path */
8053 lc = 1;
8054 } else if (CUR == '/') {
8055 /* relative or absolute location path */
8056 lc = 1;
8057 } else if (CUR == '@') {
8058 /* relative abbreviated attribute location path */
8059 lc = 1;
8060 } else if (CUR == '.') {
8061 /* relative abbreviated attribute location path */
8062 lc = 1;
8063 } else {
8064 /*
8065 * Problem is finding if we have a name here whether it's:
8066 * - a nodetype
8067 * - a function call in which case it's followed by '('
8068 * - an axis in which case it's followed by ':'
8069 * - a element name
8070 * We do an a priori analysis here rather than having to
8071 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008072 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008073 * read/write/debug.
8074 */
8075 SKIP_BLANKS;
8076 name = xmlXPathScanName(ctxt);
8077 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8078#ifdef DEBUG_STEP
8079 xmlGenericError(xmlGenericErrorContext,
8080 "PathExpr: Axis\n");
8081#endif
8082 lc = 1;
8083 xmlFree(name);
8084 } else if (name != NULL) {
8085 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008086
8087
8088 while (NXT(len) != 0) {
8089 if (NXT(len) == '/') {
8090 /* element name */
8091#ifdef DEBUG_STEP
8092 xmlGenericError(xmlGenericErrorContext,
8093 "PathExpr: AbbrRelLocation\n");
8094#endif
8095 lc = 1;
8096 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008097 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008098 /* ignore blanks */
8099 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008100 } else if (NXT(len) == ':') {
8101#ifdef DEBUG_STEP
8102 xmlGenericError(xmlGenericErrorContext,
8103 "PathExpr: AbbrRelLocation\n");
8104#endif
8105 lc = 1;
8106 break;
8107 } else if ((NXT(len) == '(')) {
8108 /* Note Type or Function */
8109 if (xmlXPathIsNodeType(name)) {
8110#ifdef DEBUG_STEP
8111 xmlGenericError(xmlGenericErrorContext,
8112 "PathExpr: Type search\n");
8113#endif
8114 lc = 1;
8115 } else {
8116#ifdef DEBUG_STEP
8117 xmlGenericError(xmlGenericErrorContext,
8118 "PathExpr: function call\n");
8119#endif
8120 lc = 0;
8121 }
8122 break;
8123 } else if ((NXT(len) == '[')) {
8124 /* element name */
8125#ifdef DEBUG_STEP
8126 xmlGenericError(xmlGenericErrorContext,
8127 "PathExpr: AbbrRelLocation\n");
8128#endif
8129 lc = 1;
8130 break;
8131 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8132 (NXT(len) == '=')) {
8133 lc = 1;
8134 break;
8135 } else {
8136 lc = 1;
8137 break;
8138 }
8139 len++;
8140 }
8141 if (NXT(len) == 0) {
8142#ifdef DEBUG_STEP
8143 xmlGenericError(xmlGenericErrorContext,
8144 "PathExpr: AbbrRelLocation\n");
8145#endif
8146 /* element name */
8147 lc = 1;
8148 }
8149 xmlFree(name);
8150 } else {
William M. Brack08171912003-12-29 02:52:11 +00008151 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008152 XP_ERROR(XPATH_EXPR_ERROR);
8153 }
8154 }
8155
8156 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008157 if (CUR == '/') {
8158 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8159 } else {
8160 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008161 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008162 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008163 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008164 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008165 CHECK_ERROR;
8166 if ((CUR == '/') && (NXT(1) == '/')) {
8167 SKIP(2);
8168 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008169
8170 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8171 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8172 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8173
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008174 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008175 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008176 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008177 }
8178 }
8179 SKIP_BLANKS;
8180}
8181
8182/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008183 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008184 * @ctxt: the XPath Parser context
8185 *
8186 * [18] UnionExpr ::= PathExpr
8187 * | UnionExpr '|' PathExpr
8188 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008189 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008190 */
8191
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008192static void
8193xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8194 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008195 CHECK_ERROR;
8196 SKIP_BLANKS;
8197 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008198 int op1 = ctxt->comp->last;
8199 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008200
8201 NEXT;
8202 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008203 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008204
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008205 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8206
Owen Taylor3473f882001-02-23 17:55:21 +00008207 SKIP_BLANKS;
8208 }
Owen Taylor3473f882001-02-23 17:55:21 +00008209}
8210
8211/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008212 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008213 * @ctxt: the XPath Parser context
8214 *
8215 * [27] UnaryExpr ::= UnionExpr
8216 * | '-' UnaryExpr
8217 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008218 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008219 */
8220
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008221static void
8222xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008223 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008224 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008225
8226 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008227 while (CUR == '-') {
8228 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008229 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008230 NEXT;
8231 SKIP_BLANKS;
8232 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008233
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008234 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008235 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008236 if (found) {
8237 if (minus)
8238 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8239 else
8240 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008241 }
8242}
8243
8244/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008245 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008246 * @ctxt: the XPath Parser context
8247 *
8248 * [26] MultiplicativeExpr ::= UnaryExpr
8249 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8250 * | MultiplicativeExpr 'div' UnaryExpr
8251 * | MultiplicativeExpr 'mod' UnaryExpr
8252 * [34] MultiplyOperator ::= '*'
8253 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008254 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008255 */
8256
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008257static void
8258xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8259 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008260 CHECK_ERROR;
8261 SKIP_BLANKS;
8262 while ((CUR == '*') ||
8263 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8264 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8265 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008266 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008267
8268 if (CUR == '*') {
8269 op = 0;
8270 NEXT;
8271 } else if (CUR == 'd') {
8272 op = 1;
8273 SKIP(3);
8274 } else if (CUR == 'm') {
8275 op = 2;
8276 SKIP(3);
8277 }
8278 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008279 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008280 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008281 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008282 SKIP_BLANKS;
8283 }
8284}
8285
8286/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008287 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008288 * @ctxt: the XPath Parser context
8289 *
8290 * [25] AdditiveExpr ::= MultiplicativeExpr
8291 * | AdditiveExpr '+' MultiplicativeExpr
8292 * | AdditiveExpr '-' MultiplicativeExpr
8293 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008294 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008295 */
8296
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008297static void
8298xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008299
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008300 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008301 CHECK_ERROR;
8302 SKIP_BLANKS;
8303 while ((CUR == '+') || (CUR == '-')) {
8304 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008305 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008306
8307 if (CUR == '+') plus = 1;
8308 else plus = 0;
8309 NEXT;
8310 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008311 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008312 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008313 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008314 SKIP_BLANKS;
8315 }
8316}
8317
8318/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008319 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008320 * @ctxt: the XPath Parser context
8321 *
8322 * [24] RelationalExpr ::= AdditiveExpr
8323 * | RelationalExpr '<' AdditiveExpr
8324 * | RelationalExpr '>' AdditiveExpr
8325 * | RelationalExpr '<=' AdditiveExpr
8326 * | RelationalExpr '>=' AdditiveExpr
8327 *
8328 * A <= B > C is allowed ? Answer from James, yes with
8329 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8330 * which is basically what got implemented.
8331 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008332 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008333 * on the stack
8334 */
8335
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008336static void
8337xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8338 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008339 CHECK_ERROR;
8340 SKIP_BLANKS;
8341 while ((CUR == '<') ||
8342 (CUR == '>') ||
8343 ((CUR == '<') && (NXT(1) == '=')) ||
8344 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008345 int inf, strict;
8346 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008347
8348 if (CUR == '<') inf = 1;
8349 else inf = 0;
8350 if (NXT(1) == '=') strict = 0;
8351 else strict = 1;
8352 NEXT;
8353 if (!strict) NEXT;
8354 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008355 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008356 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008357 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008358 SKIP_BLANKS;
8359 }
8360}
8361
8362/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008363 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008364 * @ctxt: the XPath Parser context
8365 *
8366 * [23] EqualityExpr ::= RelationalExpr
8367 * | EqualityExpr '=' RelationalExpr
8368 * | EqualityExpr '!=' RelationalExpr
8369 *
8370 * A != B != C is allowed ? Answer from James, yes with
8371 * (RelationalExpr = RelationalExpr) = RelationalExpr
8372 * (RelationalExpr != RelationalExpr) != RelationalExpr
8373 * which is basically what got implemented.
8374 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008375 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008376 *
8377 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008378static void
8379xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8380 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008381 CHECK_ERROR;
8382 SKIP_BLANKS;
8383 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008384 int eq;
8385 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008386
8387 if (CUR == '=') eq = 1;
8388 else eq = 0;
8389 NEXT;
8390 if (!eq) NEXT;
8391 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008392 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008393 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008394 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008395 SKIP_BLANKS;
8396 }
8397}
8398
8399/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008400 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008401 * @ctxt: the XPath Parser context
8402 *
8403 * [22] AndExpr ::= EqualityExpr
8404 * | AndExpr 'and' EqualityExpr
8405 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008406 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008407 *
8408 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008409static void
8410xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8411 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008412 CHECK_ERROR;
8413 SKIP_BLANKS;
8414 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008415 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008416 SKIP(3);
8417 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008418 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008419 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008420 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008421 SKIP_BLANKS;
8422 }
8423}
8424
8425/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008426 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008427 * @ctxt: the XPath Parser context
8428 *
8429 * [14] Expr ::= OrExpr
8430 * [21] OrExpr ::= AndExpr
8431 * | OrExpr 'or' AndExpr
8432 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008433 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008434 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008435static void
8436xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8437 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008438 CHECK_ERROR;
8439 SKIP_BLANKS;
8440 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008441 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008442 SKIP(2);
8443 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008444 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008445 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008446 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8447 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008448 SKIP_BLANKS;
8449 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008450 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8451 /* more ops could be optimized too */
8452 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8453 }
Owen Taylor3473f882001-02-23 17:55:21 +00008454}
8455
8456/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008457 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008458 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008459 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008460 *
8461 * [8] Predicate ::= '[' PredicateExpr ']'
8462 * [9] PredicateExpr ::= Expr
8463 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008464 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008465 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008466static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008467xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008468 int op1 = ctxt->comp->last;
8469
8470 SKIP_BLANKS;
8471 if (CUR != '[') {
8472 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8473 }
8474 NEXT;
8475 SKIP_BLANKS;
8476
8477 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008478 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008479 CHECK_ERROR;
8480
8481 if (CUR != ']') {
8482 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8483 }
8484
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008485 if (filter)
8486 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8487 else
8488 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008489
8490 NEXT;
8491 SKIP_BLANKS;
8492}
8493
8494/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008495 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008496 * @ctxt: the XPath Parser context
8497 * @test: pointer to a xmlXPathTestVal
8498 * @type: pointer to a xmlXPathTypeVal
8499 * @prefix: placeholder for a possible name prefix
8500 *
8501 * [7] NodeTest ::= NameTest
8502 * | NodeType '(' ')'
8503 * | 'processing-instruction' '(' Literal ')'
8504 *
8505 * [37] NameTest ::= '*'
8506 * | NCName ':' '*'
8507 * | QName
8508 * [38] NodeType ::= 'comment'
8509 * | 'text'
8510 * | 'processing-instruction'
8511 * | 'node'
8512 *
William M. Brack08171912003-12-29 02:52:11 +00008513 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00008514 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008515static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008516xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8517 xmlXPathTypeVal *type, const xmlChar **prefix,
8518 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008519 int blanks;
8520
8521 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8522 STRANGE;
8523 return(NULL);
8524 }
William M. Brack78637da2003-07-31 14:47:38 +00008525 *type = (xmlXPathTypeVal) 0;
8526 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008527 *prefix = NULL;
8528 SKIP_BLANKS;
8529
8530 if ((name == NULL) && (CUR == '*')) {
8531 /*
8532 * All elements
8533 */
8534 NEXT;
8535 *test = NODE_TEST_ALL;
8536 return(NULL);
8537 }
8538
8539 if (name == NULL)
8540 name = xmlXPathParseNCName(ctxt);
8541 if (name == NULL) {
8542 XP_ERROR0(XPATH_EXPR_ERROR);
8543 }
8544
William M. Brack76e95df2003-10-18 16:20:14 +00008545 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008546 SKIP_BLANKS;
8547 if (CUR == '(') {
8548 NEXT;
8549 /*
8550 * NodeType or PI search
8551 */
8552 if (xmlStrEqual(name, BAD_CAST "comment"))
8553 *type = NODE_TYPE_COMMENT;
8554 else if (xmlStrEqual(name, BAD_CAST "node"))
8555 *type = NODE_TYPE_NODE;
8556 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8557 *type = NODE_TYPE_PI;
8558 else if (xmlStrEqual(name, BAD_CAST "text"))
8559 *type = NODE_TYPE_TEXT;
8560 else {
8561 if (name != NULL)
8562 xmlFree(name);
8563 XP_ERROR0(XPATH_EXPR_ERROR);
8564 }
8565
8566 *test = NODE_TEST_TYPE;
8567
8568 SKIP_BLANKS;
8569 if (*type == NODE_TYPE_PI) {
8570 /*
8571 * Specific case: search a PI by name.
8572 */
Owen Taylor3473f882001-02-23 17:55:21 +00008573 if (name != NULL)
8574 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008575 name = NULL;
8576 if (CUR != ')') {
8577 name = xmlXPathParseLiteral(ctxt);
8578 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008579 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008580 SKIP_BLANKS;
8581 }
Owen Taylor3473f882001-02-23 17:55:21 +00008582 }
8583 if (CUR != ')') {
8584 if (name != NULL)
8585 xmlFree(name);
8586 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8587 }
8588 NEXT;
8589 return(name);
8590 }
8591 *test = NODE_TEST_NAME;
8592 if ((!blanks) && (CUR == ':')) {
8593 NEXT;
8594
8595 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008596 * Since currently the parser context don't have a
8597 * namespace list associated:
8598 * The namespace name for this prefix can be computed
8599 * only at evaluation time. The compilation is done
8600 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008601 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008602#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008603 *prefix = xmlXPathNsLookup(ctxt->context, name);
8604 if (name != NULL)
8605 xmlFree(name);
8606 if (*prefix == NULL) {
8607 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8608 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008609#else
8610 *prefix = name;
8611#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008612
8613 if (CUR == '*') {
8614 /*
8615 * All elements
8616 */
8617 NEXT;
8618 *test = NODE_TEST_ALL;
8619 return(NULL);
8620 }
8621
8622 name = xmlXPathParseNCName(ctxt);
8623 if (name == NULL) {
8624 XP_ERROR0(XPATH_EXPR_ERROR);
8625 }
8626 }
8627 return(name);
8628}
8629
8630/**
8631 * xmlXPathIsAxisName:
8632 * @name: a preparsed name token
8633 *
8634 * [6] AxisName ::= 'ancestor'
8635 * | 'ancestor-or-self'
8636 * | 'attribute'
8637 * | 'child'
8638 * | 'descendant'
8639 * | 'descendant-or-self'
8640 * | 'following'
8641 * | 'following-sibling'
8642 * | 'namespace'
8643 * | 'parent'
8644 * | 'preceding'
8645 * | 'preceding-sibling'
8646 * | 'self'
8647 *
8648 * Returns the axis or 0
8649 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008650static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008651xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008652 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008653 switch (name[0]) {
8654 case 'a':
8655 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8656 ret = AXIS_ANCESTOR;
8657 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8658 ret = AXIS_ANCESTOR_OR_SELF;
8659 if (xmlStrEqual(name, BAD_CAST "attribute"))
8660 ret = AXIS_ATTRIBUTE;
8661 break;
8662 case 'c':
8663 if (xmlStrEqual(name, BAD_CAST "child"))
8664 ret = AXIS_CHILD;
8665 break;
8666 case 'd':
8667 if (xmlStrEqual(name, BAD_CAST "descendant"))
8668 ret = AXIS_DESCENDANT;
8669 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8670 ret = AXIS_DESCENDANT_OR_SELF;
8671 break;
8672 case 'f':
8673 if (xmlStrEqual(name, BAD_CAST "following"))
8674 ret = AXIS_FOLLOWING;
8675 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8676 ret = AXIS_FOLLOWING_SIBLING;
8677 break;
8678 case 'n':
8679 if (xmlStrEqual(name, BAD_CAST "namespace"))
8680 ret = AXIS_NAMESPACE;
8681 break;
8682 case 'p':
8683 if (xmlStrEqual(name, BAD_CAST "parent"))
8684 ret = AXIS_PARENT;
8685 if (xmlStrEqual(name, BAD_CAST "preceding"))
8686 ret = AXIS_PRECEDING;
8687 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8688 ret = AXIS_PRECEDING_SIBLING;
8689 break;
8690 case 's':
8691 if (xmlStrEqual(name, BAD_CAST "self"))
8692 ret = AXIS_SELF;
8693 break;
8694 }
8695 return(ret);
8696}
8697
8698/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008699 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008700 * @ctxt: the XPath Parser context
8701 *
8702 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8703 * | AbbreviatedStep
8704 *
8705 * [12] AbbreviatedStep ::= '.' | '..'
8706 *
8707 * [5] AxisSpecifier ::= AxisName '::'
8708 * | AbbreviatedAxisSpecifier
8709 *
8710 * [13] AbbreviatedAxisSpecifier ::= '@'?
8711 *
8712 * Modified for XPtr range support as:
8713 *
8714 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8715 * | AbbreviatedStep
8716 * | 'range-to' '(' Expr ')' Predicate*
8717 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008718 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008719 * A location step of . is short for self::node(). This is
8720 * particularly useful in conjunction with //. For example, the
8721 * location path .//para is short for
8722 * self::node()/descendant-or-self::node()/child::para
8723 * and so will select all para descendant elements of the context
8724 * node.
8725 * Similarly, a location step of .. is short for parent::node().
8726 * For example, ../title is short for parent::node()/child::title
8727 * and so will select the title children of the parent of the context
8728 * node.
8729 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008730static void
8731xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008732#ifdef LIBXML_XPTR_ENABLED
8733 int rangeto = 0;
8734 int op2 = -1;
8735#endif
8736
Owen Taylor3473f882001-02-23 17:55:21 +00008737 SKIP_BLANKS;
8738 if ((CUR == '.') && (NXT(1) == '.')) {
8739 SKIP(2);
8740 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008741 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8742 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008743 } else if (CUR == '.') {
8744 NEXT;
8745 SKIP_BLANKS;
8746 } else {
8747 xmlChar *name = NULL;
8748 const xmlChar *prefix = NULL;
8749 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008750 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008751 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008752 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008753
8754 /*
8755 * The modification needed for XPointer change to the production
8756 */
8757#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008758 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008759 name = xmlXPathParseNCName(ctxt);
8760 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008761 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008762 xmlFree(name);
8763 SKIP_BLANKS;
8764 if (CUR != '(') {
8765 XP_ERROR(XPATH_EXPR_ERROR);
8766 }
8767 NEXT;
8768 SKIP_BLANKS;
8769
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008770 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008771 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008772 CHECK_ERROR;
8773
8774 SKIP_BLANKS;
8775 if (CUR != ')') {
8776 XP_ERROR(XPATH_EXPR_ERROR);
8777 }
8778 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008779 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008780 goto eval_predicates;
8781 }
8782 }
8783#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008784 if (CUR == '*') {
8785 axis = AXIS_CHILD;
8786 } else {
8787 if (name == NULL)
8788 name = xmlXPathParseNCName(ctxt);
8789 if (name != NULL) {
8790 axis = xmlXPathIsAxisName(name);
8791 if (axis != 0) {
8792 SKIP_BLANKS;
8793 if ((CUR == ':') && (NXT(1) == ':')) {
8794 SKIP(2);
8795 xmlFree(name);
8796 name = NULL;
8797 } else {
8798 /* an element name can conflict with an axis one :-\ */
8799 axis = AXIS_CHILD;
8800 }
Owen Taylor3473f882001-02-23 17:55:21 +00008801 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008802 axis = AXIS_CHILD;
8803 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008804 } else if (CUR == '@') {
8805 NEXT;
8806 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008807 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008808 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008809 }
Owen Taylor3473f882001-02-23 17:55:21 +00008810 }
8811
8812 CHECK_ERROR;
8813
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008814 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008815 if (test == 0)
8816 return;
8817
8818#ifdef DEBUG_STEP
8819 xmlGenericError(xmlGenericErrorContext,
8820 "Basis : computing new set\n");
8821#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008822
Owen Taylor3473f882001-02-23 17:55:21 +00008823#ifdef DEBUG_STEP
8824 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008825 if (ctxt->value == NULL)
8826 xmlGenericError(xmlGenericErrorContext, "no value\n");
8827 else if (ctxt->value->nodesetval == NULL)
8828 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8829 else
8830 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008831#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008832
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008833#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008834eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008835#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008836 op1 = ctxt->comp->last;
8837 ctxt->comp->last = -1;
8838
Owen Taylor3473f882001-02-23 17:55:21 +00008839 SKIP_BLANKS;
8840 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008841 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008842 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008843
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008844#ifdef LIBXML_XPTR_ENABLED
8845 if (rangeto) {
8846 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8847 } else
8848#endif
8849 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8850 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008851
Owen Taylor3473f882001-02-23 17:55:21 +00008852 }
8853#ifdef DEBUG_STEP
8854 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008855 if (ctxt->value == NULL)
8856 xmlGenericError(xmlGenericErrorContext, "no value\n");
8857 else if (ctxt->value->nodesetval == NULL)
8858 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8859 else
8860 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8861 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008862#endif
8863}
8864
8865/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008866 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008867 * @ctxt: the XPath Parser context
8868 *
8869 * [3] RelativeLocationPath ::= Step
8870 * | RelativeLocationPath '/' Step
8871 * | AbbreviatedRelativeLocationPath
8872 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8873 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008874 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008875 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008876static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008877xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008878(xmlXPathParserContextPtr ctxt) {
8879 SKIP_BLANKS;
8880 if ((CUR == '/') && (NXT(1) == '/')) {
8881 SKIP(2);
8882 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008883 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8884 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008885 } else if (CUR == '/') {
8886 NEXT;
8887 SKIP_BLANKS;
8888 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008889 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008890 SKIP_BLANKS;
8891 while (CUR == '/') {
8892 if ((CUR == '/') && (NXT(1) == '/')) {
8893 SKIP(2);
8894 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008895 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008896 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008897 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008898 } else if (CUR == '/') {
8899 NEXT;
8900 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008901 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008902 }
8903 SKIP_BLANKS;
8904 }
8905}
8906
8907/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008908 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008909 * @ctxt: the XPath Parser context
8910 *
8911 * [1] LocationPath ::= RelativeLocationPath
8912 * | AbsoluteLocationPath
8913 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8914 * | AbbreviatedAbsoluteLocationPath
8915 * [10] AbbreviatedAbsoluteLocationPath ::=
8916 * '//' RelativeLocationPath
8917 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008918 * Compile a location path
8919 *
Owen Taylor3473f882001-02-23 17:55:21 +00008920 * // is short for /descendant-or-self::node()/. For example,
8921 * //para is short for /descendant-or-self::node()/child::para and
8922 * so will select any para element in the document (even a para element
8923 * that is a document element will be selected by //para since the
8924 * document element node is a child of the root node); div//para is
8925 * short for div/descendant-or-self::node()/child::para and so will
8926 * select all para descendants of div children.
8927 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008928static void
8929xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008930 SKIP_BLANKS;
8931 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008932 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008933 } else {
8934 while (CUR == '/') {
8935 if ((CUR == '/') && (NXT(1) == '/')) {
8936 SKIP(2);
8937 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008938 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8939 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008940 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008941 } else if (CUR == '/') {
8942 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008943 SKIP_BLANKS;
8944 if ((CUR != 0 ) &&
William M. Brack76e95df2003-10-18 16:20:14 +00008945 ((IS_LETTER_CH(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00008946 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008947 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008948 }
8949 }
8950 }
8951}
8952
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008953/************************************************************************
8954 * *
8955 * XPath precompiled expression evaluation *
8956 * *
8957 ************************************************************************/
8958
Daniel Veillardf06307e2001-07-03 10:35:50 +00008959static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008960xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8961
8962/**
8963 * xmlXPathNodeCollectAndTest:
8964 * @ctxt: the XPath Parser context
8965 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008966 * @first: pointer to the first element in document order
8967 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008968 *
8969 * This is the function implementing a step: based on the current list
8970 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00008971 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008972 *
8973 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008974 *
William M. Brack08171912003-12-29 02:52:11 +00008975 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008976 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008977static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008978xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008979 xmlXPathStepOpPtr op,
8980 xmlNodePtr * first, xmlNodePtr * last)
8981{
William M. Brack78637da2003-07-31 14:47:38 +00008982 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
8983 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
8984 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008985 const xmlChar *prefix = op->value4;
8986 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008987 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008988
8989#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008990 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008991#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008992 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008993 xmlNodeSetPtr ret, list;
8994 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008995 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008996 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008997 xmlNodePtr cur = NULL;
8998 xmlXPathObjectPtr obj;
8999 xmlNodeSetPtr nodelist;
9000 xmlNodePtr tmp;
9001
Daniel Veillardf06307e2001-07-03 10:35:50 +00009002 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009003 obj = valuePop(ctxt);
9004 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009005 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009006 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009007 URI = xmlXPathNsLookup(ctxt->context, prefix);
9008 if (URI == NULL)
9009 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00009010 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009011#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009012 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009013#endif
9014 switch (axis) {
9015 case AXIS_ANCESTOR:
9016#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009017 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009018#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009019 first = NULL;
9020 next = xmlXPathNextAncestor;
9021 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009022 case AXIS_ANCESTOR_OR_SELF:
9023#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009024 xmlGenericError(xmlGenericErrorContext,
9025 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009026#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009027 first = NULL;
9028 next = xmlXPathNextAncestorOrSelf;
9029 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009030 case AXIS_ATTRIBUTE:
9031#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009032 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009033#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009034 first = NULL;
9035 last = NULL;
9036 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009037 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009038 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009039 case AXIS_CHILD:
9040#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009041 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009042#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009043 last = NULL;
9044 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009045 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009046 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009047 case AXIS_DESCENDANT:
9048#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009049 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009050#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009051 last = NULL;
9052 next = xmlXPathNextDescendant;
9053 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009054 case AXIS_DESCENDANT_OR_SELF:
9055#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009056 xmlGenericError(xmlGenericErrorContext,
9057 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009058#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009059 last = NULL;
9060 next = xmlXPathNextDescendantOrSelf;
9061 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009062 case AXIS_FOLLOWING:
9063#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009064 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009065#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009066 last = NULL;
9067 next = xmlXPathNextFollowing;
9068 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009069 case AXIS_FOLLOWING_SIBLING:
9070#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009071 xmlGenericError(xmlGenericErrorContext,
9072 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009073#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009074 last = NULL;
9075 next = xmlXPathNextFollowingSibling;
9076 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009077 case AXIS_NAMESPACE:
9078#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009079 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009080#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009081 first = NULL;
9082 last = NULL;
9083 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009084 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009085 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009086 case AXIS_PARENT:
9087#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009088 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009089#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009090 first = NULL;
9091 next = xmlXPathNextParent;
9092 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009093 case AXIS_PRECEDING:
9094#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009095 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009096#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009097 first = NULL;
9098 next = xmlXPathNextPrecedingInternal;
9099 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009100 case AXIS_PRECEDING_SIBLING:
9101#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009102 xmlGenericError(xmlGenericErrorContext,
9103 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009104#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009105 first = NULL;
9106 next = xmlXPathNextPrecedingSibling;
9107 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009108 case AXIS_SELF:
9109#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009110 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009111#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009112 first = NULL;
9113 last = NULL;
9114 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009115 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009116 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009117 }
9118 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009119 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009120
9121 nodelist = obj->nodesetval;
9122 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009123 xmlXPathFreeObject(obj);
9124 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9125 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009126 }
9127 addNode = xmlXPathNodeSetAddUnique;
9128 ret = NULL;
9129#ifdef DEBUG_STEP
9130 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009131 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009132 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009133 case NODE_TEST_NONE:
9134 xmlGenericError(xmlGenericErrorContext,
9135 " searching for none !!!\n");
9136 break;
9137 case NODE_TEST_TYPE:
9138 xmlGenericError(xmlGenericErrorContext,
9139 " searching for type %d\n", type);
9140 break;
9141 case NODE_TEST_PI:
9142 xmlGenericError(xmlGenericErrorContext,
9143 " searching for PI !!!\n");
9144 break;
9145 case NODE_TEST_ALL:
9146 xmlGenericError(xmlGenericErrorContext,
9147 " searching for *\n");
9148 break;
9149 case NODE_TEST_NS:
9150 xmlGenericError(xmlGenericErrorContext,
9151 " searching for namespace %s\n",
9152 prefix);
9153 break;
9154 case NODE_TEST_NAME:
9155 xmlGenericError(xmlGenericErrorContext,
9156 " searching for name %s\n", name);
9157 if (prefix != NULL)
9158 xmlGenericError(xmlGenericErrorContext,
9159 " with namespace %s\n", prefix);
9160 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009161 }
9162 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9163#endif
9164 /*
9165 * 2.3 Node Tests
9166 * - For the attribute axis, the principal node type is attribute.
9167 * - For the namespace axis, the principal node type is namespace.
9168 * - For other axes, the principal node type is element.
9169 *
9170 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009171 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009172 * select all element children of the context node
9173 */
9174 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009175 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009176 ctxt->context->node = nodelist->nodeTab[i];
9177
Daniel Veillardf06307e2001-07-03 10:35:50 +00009178 cur = NULL;
9179 list = xmlXPathNodeSetCreate(NULL);
9180 do {
9181 cur = next(ctxt, cur);
9182 if (cur == NULL)
9183 break;
9184 if ((first != NULL) && (*first == cur))
9185 break;
9186 if (((t % 256) == 0) &&
9187 (first != NULL) && (*first != NULL) &&
9188 (xmlXPathCmpNodes(*first, cur) >= 0))
9189 break;
9190 if ((last != NULL) && (*last == cur))
9191 break;
9192 if (((t % 256) == 0) &&
9193 (last != NULL) && (*last != NULL) &&
9194 (xmlXPathCmpNodes(cur, *last) >= 0))
9195 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009196 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009197#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009198 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9199#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009200 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009201 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009202 ctxt->context->node = tmp;
9203 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009204 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009205 if ((cur->type == type) ||
9206 ((type == NODE_TYPE_NODE) &&
9207 ((cur->type == XML_DOCUMENT_NODE) ||
9208 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9209 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009210 (cur->type == XML_NAMESPACE_DECL) ||
9211 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009212 (cur->type == XML_PI_NODE) ||
9213 (cur->type == XML_COMMENT_NODE) ||
9214 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009215 (cur->type == XML_TEXT_NODE))) ||
9216 ((type == NODE_TYPE_TEXT) &&
9217 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009218#ifdef DEBUG_STEP
9219 n++;
9220#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009221 addNode(list, cur);
9222 }
9223 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009224 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009225 if (cur->type == XML_PI_NODE) {
9226 if ((name != NULL) &&
9227 (!xmlStrEqual(name, cur->name)))
9228 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009229#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009230 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009231#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009232 addNode(list, cur);
9233 }
9234 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009235 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009236 if (axis == AXIS_ATTRIBUTE) {
9237 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009238#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009239 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009240#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009241 addNode(list, cur);
9242 }
9243 } else if (axis == AXIS_NAMESPACE) {
9244 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009245#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009246 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009247#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009248 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9249 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009250 }
9251 } else {
9252 if (cur->type == XML_ELEMENT_NODE) {
9253 if (prefix == NULL) {
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 } else if ((cur->ns != NULL) &&
9259 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009260#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009261 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009262#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009263 addNode(list, cur);
9264 }
9265 }
9266 }
9267 break;
9268 case NODE_TEST_NS:{
9269 TODO;
9270 break;
9271 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009272 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009273 switch (cur->type) {
9274 case XML_ELEMENT_NODE:
9275 if (xmlStrEqual(name, cur->name)) {
9276 if (prefix == NULL) {
9277 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009278#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009279 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009280#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009281 addNode(list, cur);
9282 }
9283 } else {
9284 if ((cur->ns != NULL) &&
9285 (xmlStrEqual(URI,
9286 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009287#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009288 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009289#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009290 addNode(list, cur);
9291 }
9292 }
9293 }
9294 break;
9295 case XML_ATTRIBUTE_NODE:{
9296 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009297
Daniel Veillardf06307e2001-07-03 10:35:50 +00009298 if (xmlStrEqual(name, attr->name)) {
9299 if (prefix == NULL) {
9300 if ((attr->ns == NULL) ||
9301 (attr->ns->prefix == NULL)) {
9302#ifdef DEBUG_STEP
9303 n++;
9304#endif
9305 addNode(list,
9306 (xmlNodePtr) attr);
9307 }
9308 } else {
9309 if ((attr->ns != NULL) &&
9310 (xmlStrEqual(URI,
9311 attr->ns->
9312 href))) {
9313#ifdef DEBUG_STEP
9314 n++;
9315#endif
9316 addNode(list,
9317 (xmlNodePtr) attr);
9318 }
9319 }
9320 }
9321 break;
9322 }
9323 case XML_NAMESPACE_DECL:
9324 if (cur->type == XML_NAMESPACE_DECL) {
9325 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009326
Daniel Veillardf06307e2001-07-03 10:35:50 +00009327 if ((ns->prefix != NULL) && (name != NULL)
9328 && (xmlStrEqual(ns->prefix, name))) {
9329#ifdef DEBUG_STEP
9330 n++;
9331#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009332 xmlXPathNodeSetAddNs(list,
9333 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009334 }
9335 }
9336 break;
9337 default:
9338 break;
9339 }
9340 break;
9341 break;
9342 }
9343 } while (cur != NULL);
9344
9345 /*
9346 * If there is some predicate filtering do it now
9347 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009348 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009349 xmlXPathObjectPtr obj2;
9350
9351 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9352 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9353 CHECK_TYPE0(XPATH_NODESET);
9354 obj2 = valuePop(ctxt);
9355 list = obj2->nodesetval;
9356 obj2->nodesetval = NULL;
9357 xmlXPathFreeObject(obj2);
9358 }
9359 if (ret == NULL) {
9360 ret = list;
9361 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009362 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009363 xmlXPathFreeNodeSet(list);
9364 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009365 }
9366 ctxt->context->node = tmp;
9367#ifdef DEBUG_STEP
9368 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009369 "\nExamined %d nodes, found %d nodes at that step\n",
9370 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009371#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009372 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009373 if ((obj->boolval) && (obj->user != NULL)) {
9374 ctxt->value->boolval = 1;
9375 ctxt->value->user = obj->user;
9376 obj->user = NULL;
9377 obj->boolval = 0;
9378 }
9379 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009380 return(t);
9381}
9382
9383/**
9384 * xmlXPathNodeCollectAndTestNth:
9385 * @ctxt: the XPath Parser context
9386 * @op: the XPath precompiled step operation
9387 * @indx: the index to collect
9388 * @first: pointer to the first element in document order
9389 * @last: pointer to the last element in document order
9390 *
9391 * This is the function implementing a step: based on the current list
9392 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009393 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009394 *
9395 * Pushes the new NodeSet resulting from the search.
9396 * Returns the number of node traversed
9397 */
9398static int
9399xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9400 xmlXPathStepOpPtr op, int indx,
9401 xmlNodePtr * first, xmlNodePtr * last)
9402{
William M. Brack78637da2003-07-31 14:47:38 +00009403 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9404 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9405 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009406 const xmlChar *prefix = op->value4;
9407 const xmlChar *name = op->value5;
9408 const xmlChar *URI = NULL;
9409 int n = 0, t = 0;
9410
9411 int i;
9412 xmlNodeSetPtr list;
9413 xmlXPathTraversalFunction next = NULL;
9414 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9415 xmlNodePtr cur = NULL;
9416 xmlXPathObjectPtr obj;
9417 xmlNodeSetPtr nodelist;
9418 xmlNodePtr tmp;
9419
9420 CHECK_TYPE0(XPATH_NODESET);
9421 obj = valuePop(ctxt);
9422 addNode = xmlXPathNodeSetAdd;
9423 if (prefix != NULL) {
9424 URI = xmlXPathNsLookup(ctxt->context, prefix);
9425 if (URI == NULL)
9426 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9427 }
9428#ifdef DEBUG_STEP_NTH
9429 xmlGenericError(xmlGenericErrorContext, "new step : ");
9430 if (first != NULL) {
9431 if (*first != NULL)
9432 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9433 (*first)->name);
9434 else
9435 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9436 }
9437 if (last != NULL) {
9438 if (*last != NULL)
9439 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9440 (*last)->name);
9441 else
9442 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9443 }
9444#endif
9445 switch (axis) {
9446 case AXIS_ANCESTOR:
9447#ifdef DEBUG_STEP_NTH
9448 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9449#endif
9450 first = NULL;
9451 next = xmlXPathNextAncestor;
9452 break;
9453 case AXIS_ANCESTOR_OR_SELF:
9454#ifdef DEBUG_STEP_NTH
9455 xmlGenericError(xmlGenericErrorContext,
9456 "axis 'ancestors-or-self' ");
9457#endif
9458 first = NULL;
9459 next = xmlXPathNextAncestorOrSelf;
9460 break;
9461 case AXIS_ATTRIBUTE:
9462#ifdef DEBUG_STEP_NTH
9463 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9464#endif
9465 first = NULL;
9466 last = NULL;
9467 next = xmlXPathNextAttribute;
9468 break;
9469 case AXIS_CHILD:
9470#ifdef DEBUG_STEP_NTH
9471 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9472#endif
9473 last = NULL;
9474 next = xmlXPathNextChild;
9475 break;
9476 case AXIS_DESCENDANT:
9477#ifdef DEBUG_STEP_NTH
9478 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9479#endif
9480 last = NULL;
9481 next = xmlXPathNextDescendant;
9482 break;
9483 case AXIS_DESCENDANT_OR_SELF:
9484#ifdef DEBUG_STEP_NTH
9485 xmlGenericError(xmlGenericErrorContext,
9486 "axis 'descendant-or-self' ");
9487#endif
9488 last = NULL;
9489 next = xmlXPathNextDescendantOrSelf;
9490 break;
9491 case AXIS_FOLLOWING:
9492#ifdef DEBUG_STEP_NTH
9493 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9494#endif
9495 last = NULL;
9496 next = xmlXPathNextFollowing;
9497 break;
9498 case AXIS_FOLLOWING_SIBLING:
9499#ifdef DEBUG_STEP_NTH
9500 xmlGenericError(xmlGenericErrorContext,
9501 "axis 'following-siblings' ");
9502#endif
9503 last = NULL;
9504 next = xmlXPathNextFollowingSibling;
9505 break;
9506 case AXIS_NAMESPACE:
9507#ifdef DEBUG_STEP_NTH
9508 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9509#endif
9510 last = NULL;
9511 first = NULL;
9512 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9513 break;
9514 case AXIS_PARENT:
9515#ifdef DEBUG_STEP_NTH
9516 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9517#endif
9518 first = NULL;
9519 next = xmlXPathNextParent;
9520 break;
9521 case AXIS_PRECEDING:
9522#ifdef DEBUG_STEP_NTH
9523 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9524#endif
9525 first = NULL;
9526 next = xmlXPathNextPrecedingInternal;
9527 break;
9528 case AXIS_PRECEDING_SIBLING:
9529#ifdef DEBUG_STEP_NTH
9530 xmlGenericError(xmlGenericErrorContext,
9531 "axis 'preceding-sibling' ");
9532#endif
9533 first = NULL;
9534 next = xmlXPathNextPrecedingSibling;
9535 break;
9536 case AXIS_SELF:
9537#ifdef DEBUG_STEP_NTH
9538 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9539#endif
9540 first = NULL;
9541 last = NULL;
9542 next = xmlXPathNextSelf;
9543 break;
9544 }
9545 if (next == NULL)
9546 return(0);
9547
9548 nodelist = obj->nodesetval;
9549 if (nodelist == NULL) {
9550 xmlXPathFreeObject(obj);
9551 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9552 return(0);
9553 }
9554 addNode = xmlXPathNodeSetAddUnique;
9555#ifdef DEBUG_STEP_NTH
9556 xmlGenericError(xmlGenericErrorContext,
9557 " context contains %d nodes\n", nodelist->nodeNr);
9558 switch (test) {
9559 case NODE_TEST_NONE:
9560 xmlGenericError(xmlGenericErrorContext,
9561 " searching for none !!!\n");
9562 break;
9563 case NODE_TEST_TYPE:
9564 xmlGenericError(xmlGenericErrorContext,
9565 " searching for type %d\n", type);
9566 break;
9567 case NODE_TEST_PI:
9568 xmlGenericError(xmlGenericErrorContext,
9569 " searching for PI !!!\n");
9570 break;
9571 case NODE_TEST_ALL:
9572 xmlGenericError(xmlGenericErrorContext,
9573 " searching for *\n");
9574 break;
9575 case NODE_TEST_NS:
9576 xmlGenericError(xmlGenericErrorContext,
9577 " searching for namespace %s\n",
9578 prefix);
9579 break;
9580 case NODE_TEST_NAME:
9581 xmlGenericError(xmlGenericErrorContext,
9582 " searching for name %s\n", name);
9583 if (prefix != NULL)
9584 xmlGenericError(xmlGenericErrorContext,
9585 " with namespace %s\n", prefix);
9586 break;
9587 }
9588 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9589#endif
9590 /*
9591 * 2.3 Node Tests
9592 * - For the attribute axis, the principal node type is attribute.
9593 * - For the namespace axis, the principal node type is namespace.
9594 * - For other axes, the principal node type is element.
9595 *
9596 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009597 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009598 * select all element children of the context node
9599 */
9600 tmp = ctxt->context->node;
9601 list = xmlXPathNodeSetCreate(NULL);
9602 for (i = 0; i < nodelist->nodeNr; i++) {
9603 ctxt->context->node = nodelist->nodeTab[i];
9604
9605 cur = NULL;
9606 n = 0;
9607 do {
9608 cur = next(ctxt, cur);
9609 if (cur == NULL)
9610 break;
9611 if ((first != NULL) && (*first == cur))
9612 break;
9613 if (((t % 256) == 0) &&
9614 (first != NULL) && (*first != NULL) &&
9615 (xmlXPathCmpNodes(*first, cur) >= 0))
9616 break;
9617 if ((last != NULL) && (*last == cur))
9618 break;
9619 if (((t % 256) == 0) &&
9620 (last != NULL) && (*last != NULL) &&
9621 (xmlXPathCmpNodes(cur, *last) >= 0))
9622 break;
9623 t++;
9624 switch (test) {
9625 case NODE_TEST_NONE:
9626 ctxt->context->node = tmp;
9627 STRANGE return(0);
9628 case NODE_TEST_TYPE:
9629 if ((cur->type == type) ||
9630 ((type == NODE_TYPE_NODE) &&
9631 ((cur->type == XML_DOCUMENT_NODE) ||
9632 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9633 (cur->type == XML_ELEMENT_NODE) ||
9634 (cur->type == XML_PI_NODE) ||
9635 (cur->type == XML_COMMENT_NODE) ||
9636 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009637 (cur->type == XML_TEXT_NODE))) ||
9638 ((type == NODE_TYPE_TEXT) &&
9639 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009640 n++;
9641 if (n == indx)
9642 addNode(list, cur);
9643 }
9644 break;
9645 case NODE_TEST_PI:
9646 if (cur->type == XML_PI_NODE) {
9647 if ((name != NULL) &&
9648 (!xmlStrEqual(name, cur->name)))
9649 break;
9650 n++;
9651 if (n == indx)
9652 addNode(list, cur);
9653 }
9654 break;
9655 case NODE_TEST_ALL:
9656 if (axis == AXIS_ATTRIBUTE) {
9657 if (cur->type == XML_ATTRIBUTE_NODE) {
9658 n++;
9659 if (n == indx)
9660 addNode(list, cur);
9661 }
9662 } else if (axis == AXIS_NAMESPACE) {
9663 if (cur->type == XML_NAMESPACE_DECL) {
9664 n++;
9665 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009666 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9667 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009668 }
9669 } else {
9670 if (cur->type == XML_ELEMENT_NODE) {
9671 if (prefix == NULL) {
9672 n++;
9673 if (n == indx)
9674 addNode(list, cur);
9675 } else if ((cur->ns != NULL) &&
9676 (xmlStrEqual(URI, cur->ns->href))) {
9677 n++;
9678 if (n == indx)
9679 addNode(list, cur);
9680 }
9681 }
9682 }
9683 break;
9684 case NODE_TEST_NS:{
9685 TODO;
9686 break;
9687 }
9688 case NODE_TEST_NAME:
9689 switch (cur->type) {
9690 case XML_ELEMENT_NODE:
9691 if (xmlStrEqual(name, cur->name)) {
9692 if (prefix == NULL) {
9693 if (cur->ns == NULL) {
9694 n++;
9695 if (n == indx)
9696 addNode(list, cur);
9697 }
9698 } else {
9699 if ((cur->ns != NULL) &&
9700 (xmlStrEqual(URI,
9701 cur->ns->href))) {
9702 n++;
9703 if (n == indx)
9704 addNode(list, cur);
9705 }
9706 }
9707 }
9708 break;
9709 case XML_ATTRIBUTE_NODE:{
9710 xmlAttrPtr attr = (xmlAttrPtr) cur;
9711
9712 if (xmlStrEqual(name, attr->name)) {
9713 if (prefix == NULL) {
9714 if ((attr->ns == NULL) ||
9715 (attr->ns->prefix == NULL)) {
9716 n++;
9717 if (n == indx)
9718 addNode(list, cur);
9719 }
9720 } else {
9721 if ((attr->ns != NULL) &&
9722 (xmlStrEqual(URI,
9723 attr->ns->
9724 href))) {
9725 n++;
9726 if (n == indx)
9727 addNode(list, cur);
9728 }
9729 }
9730 }
9731 break;
9732 }
9733 case XML_NAMESPACE_DECL:
9734 if (cur->type == XML_NAMESPACE_DECL) {
9735 xmlNsPtr ns = (xmlNsPtr) cur;
9736
9737 if ((ns->prefix != NULL) && (name != NULL)
9738 && (xmlStrEqual(ns->prefix, name))) {
9739 n++;
9740 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009741 xmlXPathNodeSetAddNs(list,
9742 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009743 }
9744 }
9745 break;
9746 default:
9747 break;
9748 }
9749 break;
9750 break;
9751 }
9752 } while (n < indx);
9753 }
9754 ctxt->context->node = tmp;
9755#ifdef DEBUG_STEP_NTH
9756 xmlGenericError(xmlGenericErrorContext,
9757 "\nExamined %d nodes, found %d nodes at that step\n",
9758 t, list->nodeNr);
9759#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009760 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009761 if ((obj->boolval) && (obj->user != NULL)) {
9762 ctxt->value->boolval = 1;
9763 ctxt->value->user = obj->user;
9764 obj->user = NULL;
9765 obj->boolval = 0;
9766 }
9767 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009768 return(t);
9769}
9770
9771/**
9772 * xmlXPathCompOpEvalFirst:
9773 * @ctxt: the XPath parser context with the compiled expression
9774 * @op: an XPath compiled operation
9775 * @first: the first elem found so far
9776 *
9777 * Evaluate the Precompiled XPath operation searching only the first
9778 * element in document order
9779 *
9780 * Returns the number of examined objects.
9781 */
9782static int
9783xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9784 xmlXPathStepOpPtr op, xmlNodePtr * first)
9785{
9786 int total = 0, cur;
9787 xmlXPathCompExprPtr comp;
9788 xmlXPathObjectPtr arg1, arg2;
9789
Daniel Veillard556c6682001-10-06 09:59:51 +00009790 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009791 comp = ctxt->comp;
9792 switch (op->op) {
9793 case XPATH_OP_END:
9794 return (0);
9795 case XPATH_OP_UNION:
9796 total =
9797 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9798 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009799 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009800 if ((ctxt->value != NULL)
9801 && (ctxt->value->type == XPATH_NODESET)
9802 && (ctxt->value->nodesetval != NULL)
9803 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9804 /*
9805 * limit tree traversing to first node in the result
9806 */
9807 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9808 *first = ctxt->value->nodesetval->nodeTab[0];
9809 }
9810 cur =
9811 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9812 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009813 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009814 CHECK_TYPE0(XPATH_NODESET);
9815 arg2 = valuePop(ctxt);
9816
9817 CHECK_TYPE0(XPATH_NODESET);
9818 arg1 = valuePop(ctxt);
9819
9820 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9821 arg2->nodesetval);
9822 valuePush(ctxt, arg1);
9823 xmlXPathFreeObject(arg2);
9824 /* optimizer */
9825 if (total > cur)
9826 xmlXPathCompSwap(op);
9827 return (total + cur);
9828 case XPATH_OP_ROOT:
9829 xmlXPathRoot(ctxt);
9830 return (0);
9831 case XPATH_OP_NODE:
9832 if (op->ch1 != -1)
9833 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009834 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009835 if (op->ch2 != -1)
9836 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009837 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009838 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9839 return (total);
9840 case XPATH_OP_RESET:
9841 if (op->ch1 != -1)
9842 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009843 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009844 if (op->ch2 != -1)
9845 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009846 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009847 ctxt->context->node = NULL;
9848 return (total);
9849 case XPATH_OP_COLLECT:{
9850 if (op->ch1 == -1)
9851 return (total);
9852
9853 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009854 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009855
9856 /*
9857 * Optimization for [n] selection where n is a number
9858 */
9859 if ((op->ch2 != -1) &&
9860 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9861 (comp->steps[op->ch2].ch1 == -1) &&
9862 (comp->steps[op->ch2].ch2 != -1) &&
9863 (comp->steps[comp->steps[op->ch2].ch2].op ==
9864 XPATH_OP_VALUE)) {
9865 xmlXPathObjectPtr val;
9866
9867 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9868 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9869 int indx = (int) val->floatval;
9870
9871 if (val->floatval == (float) indx) {
9872 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9873 first, NULL);
9874 return (total);
9875 }
9876 }
9877 }
9878 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9879 return (total);
9880 }
9881 case XPATH_OP_VALUE:
9882 valuePush(ctxt,
9883 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9884 return (0);
9885 case XPATH_OP_SORT:
9886 if (op->ch1 != -1)
9887 total +=
9888 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9889 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009890 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009891 if ((ctxt->value != NULL)
9892 && (ctxt->value->type == XPATH_NODESET)
9893 && (ctxt->value->nodesetval != NULL))
9894 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9895 return (total);
9896 default:
9897 return (xmlXPathCompOpEval(ctxt, op));
9898 }
9899}
9900
9901/**
9902 * xmlXPathCompOpEvalLast:
9903 * @ctxt: the XPath parser context with the compiled expression
9904 * @op: an XPath compiled operation
9905 * @last: the last elem found so far
9906 *
9907 * Evaluate the Precompiled XPath operation searching only the last
9908 * element in document order
9909 *
William M. Brack08171912003-12-29 02:52:11 +00009910 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +00009911 */
9912static int
9913xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9914 xmlNodePtr * last)
9915{
9916 int total = 0, cur;
9917 xmlXPathCompExprPtr comp;
9918 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +00009919 xmlNodePtr bak;
9920 xmlDocPtr bakd;
9921 int pp;
9922 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009923
Daniel Veillard556c6682001-10-06 09:59:51 +00009924 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009925 comp = ctxt->comp;
9926 switch (op->op) {
9927 case XPATH_OP_END:
9928 return (0);
9929 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +00009930 bakd = ctxt->context->doc;
9931 bak = ctxt->context->node;
9932 pp = ctxt->context->proximityPosition;
9933 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009934 total =
9935 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009936 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009937 if ((ctxt->value != NULL)
9938 && (ctxt->value->type == XPATH_NODESET)
9939 && (ctxt->value->nodesetval != NULL)
9940 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9941 /*
9942 * limit tree traversing to first node in the result
9943 */
9944 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9945 *last =
9946 ctxt->value->nodesetval->nodeTab[ctxt->value->
9947 nodesetval->nodeNr -
9948 1];
9949 }
William M. Brackce4fc562004-01-22 02:47:18 +00009950 ctxt->context->doc = bakd;
9951 ctxt->context->node = bak;
9952 ctxt->context->proximityPosition = pp;
9953 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009954 cur =
9955 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009956 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009957 if ((ctxt->value != NULL)
9958 && (ctxt->value->type == XPATH_NODESET)
9959 && (ctxt->value->nodesetval != NULL)
9960 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9961 }
9962 CHECK_TYPE0(XPATH_NODESET);
9963 arg2 = valuePop(ctxt);
9964
9965 CHECK_TYPE0(XPATH_NODESET);
9966 arg1 = valuePop(ctxt);
9967
9968 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9969 arg2->nodesetval);
9970 valuePush(ctxt, arg1);
9971 xmlXPathFreeObject(arg2);
9972 /* optimizer */
9973 if (total > cur)
9974 xmlXPathCompSwap(op);
9975 return (total + cur);
9976 case XPATH_OP_ROOT:
9977 xmlXPathRoot(ctxt);
9978 return (0);
9979 case XPATH_OP_NODE:
9980 if (op->ch1 != -1)
9981 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009982 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009983 if (op->ch2 != -1)
9984 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009985 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009986 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9987 return (total);
9988 case XPATH_OP_RESET:
9989 if (op->ch1 != -1)
9990 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009991 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009992 if (op->ch2 != -1)
9993 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009994 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009995 ctxt->context->node = NULL;
9996 return (total);
9997 case XPATH_OP_COLLECT:{
9998 if (op->ch1 == -1)
9999 return (0);
10000
10001 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010002 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010003
10004 /*
10005 * Optimization for [n] selection where n is a number
10006 */
10007 if ((op->ch2 != -1) &&
10008 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10009 (comp->steps[op->ch2].ch1 == -1) &&
10010 (comp->steps[op->ch2].ch2 != -1) &&
10011 (comp->steps[comp->steps[op->ch2].ch2].op ==
10012 XPATH_OP_VALUE)) {
10013 xmlXPathObjectPtr val;
10014
10015 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10016 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10017 int indx = (int) val->floatval;
10018
10019 if (val->floatval == (float) indx) {
10020 total +=
10021 xmlXPathNodeCollectAndTestNth(ctxt, op,
10022 indx, NULL,
10023 last);
10024 return (total);
10025 }
10026 }
10027 }
10028 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10029 return (total);
10030 }
10031 case XPATH_OP_VALUE:
10032 valuePush(ctxt,
10033 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10034 return (0);
10035 case XPATH_OP_SORT:
10036 if (op->ch1 != -1)
10037 total +=
10038 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10039 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010040 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010041 if ((ctxt->value != NULL)
10042 && (ctxt->value->type == XPATH_NODESET)
10043 && (ctxt->value->nodesetval != NULL))
10044 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10045 return (total);
10046 default:
10047 return (xmlXPathCompOpEval(ctxt, op));
10048 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010049}
10050
Owen Taylor3473f882001-02-23 17:55:21 +000010051/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010052 * xmlXPathCompOpEval:
10053 * @ctxt: the XPath parser context with the compiled expression
10054 * @op: an XPath compiled operation
10055 *
10056 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010057 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010058 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010059static int
10060xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10061{
10062 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010063 int equal, ret;
10064 xmlXPathCompExprPtr comp;
10065 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010066 xmlNodePtr bak;
10067 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010068 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010069 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010070
Daniel Veillard556c6682001-10-06 09:59:51 +000010071 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010072 comp = ctxt->comp;
10073 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010074 case XPATH_OP_END:
10075 return (0);
10076 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010077 bakd = ctxt->context->doc;
10078 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010079 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010080 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010081 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010082 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010083 xmlXPathBooleanFunction(ctxt, 1);
10084 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10085 return (total);
10086 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010087 ctxt->context->doc = bakd;
10088 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010089 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010090 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010091 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010092 if (ctxt->error) {
10093 xmlXPathFreeObject(arg2);
10094 return(0);
10095 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010096 xmlXPathBooleanFunction(ctxt, 1);
10097 arg1 = valuePop(ctxt);
10098 arg1->boolval &= arg2->boolval;
10099 valuePush(ctxt, arg1);
10100 xmlXPathFreeObject(arg2);
10101 return (total);
10102 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010103 bakd = ctxt->context->doc;
10104 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010105 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010106 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010107 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010108 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010109 xmlXPathBooleanFunction(ctxt, 1);
10110 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10111 return (total);
10112 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010113 ctxt->context->doc = bakd;
10114 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010115 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010116 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010117 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010118 if (ctxt->error) {
10119 xmlXPathFreeObject(arg2);
10120 return(0);
10121 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010122 xmlXPathBooleanFunction(ctxt, 1);
10123 arg1 = valuePop(ctxt);
10124 arg1->boolval |= arg2->boolval;
10125 valuePush(ctxt, arg1);
10126 xmlXPathFreeObject(arg2);
10127 return (total);
10128 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010129 bakd = ctxt->context->doc;
10130 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010131 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010132 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010133 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010134 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010135 ctxt->context->doc = bakd;
10136 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010137 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010138 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010139 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010140 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010141 if (op->value)
10142 equal = xmlXPathEqualValues(ctxt);
10143 else
10144 equal = xmlXPathNotEqualValues(ctxt);
10145 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010146 return (total);
10147 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010148 bakd = ctxt->context->doc;
10149 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010150 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010151 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010152 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010153 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010154 ctxt->context->doc = bakd;
10155 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010156 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010157 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010158 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010159 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010160 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10161 valuePush(ctxt, xmlXPathNewBoolean(ret));
10162 return (total);
10163 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010164 bakd = ctxt->context->doc;
10165 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010166 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010167 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010168 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010169 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010170 if (op->ch2 != -1) {
10171 ctxt->context->doc = bakd;
10172 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010173 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010174 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010175 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010176 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010177 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010178 if (op->value == 0)
10179 xmlXPathSubValues(ctxt);
10180 else if (op->value == 1)
10181 xmlXPathAddValues(ctxt);
10182 else if (op->value == 2)
10183 xmlXPathValueFlipSign(ctxt);
10184 else if (op->value == 3) {
10185 CAST_TO_NUMBER;
10186 CHECK_TYPE0(XPATH_NUMBER);
10187 }
10188 return (total);
10189 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010190 bakd = ctxt->context->doc;
10191 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010192 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010193 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010194 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010195 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010196 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 Veillard556c6682001-10-06 09:59:51 +000010201 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010202 if (op->value == 0)
10203 xmlXPathMultValues(ctxt);
10204 else if (op->value == 1)
10205 xmlXPathDivValues(ctxt);
10206 else if (op->value == 2)
10207 xmlXPathModValues(ctxt);
10208 return (total);
10209 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010210 bakd = ctxt->context->doc;
10211 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010212 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010213 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010214 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010215 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010216 ctxt->context->doc = bakd;
10217 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010218 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010219 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010220 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010221 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010222 CHECK_TYPE0(XPATH_NODESET);
10223 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010224
Daniel Veillardf06307e2001-07-03 10:35:50 +000010225 CHECK_TYPE0(XPATH_NODESET);
10226 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010227
Daniel Veillardf06307e2001-07-03 10:35:50 +000010228 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10229 arg2->nodesetval);
10230 valuePush(ctxt, arg1);
10231 xmlXPathFreeObject(arg2);
10232 return (total);
10233 case XPATH_OP_ROOT:
10234 xmlXPathRoot(ctxt);
10235 return (total);
10236 case XPATH_OP_NODE:
10237 if (op->ch1 != -1)
10238 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010239 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010240 if (op->ch2 != -1)
10241 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010242 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010243 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10244 return (total);
10245 case XPATH_OP_RESET:
10246 if (op->ch1 != -1)
10247 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010248 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010249 if (op->ch2 != -1)
10250 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010251 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010252 ctxt->context->node = NULL;
10253 return (total);
10254 case XPATH_OP_COLLECT:{
10255 if (op->ch1 == -1)
10256 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010257
Daniel Veillardf06307e2001-07-03 10:35:50 +000010258 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010259 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010260
Daniel Veillardf06307e2001-07-03 10:35:50 +000010261 /*
10262 * Optimization for [n] selection where n is a number
10263 */
10264 if ((op->ch2 != -1) &&
10265 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10266 (comp->steps[op->ch2].ch1 == -1) &&
10267 (comp->steps[op->ch2].ch2 != -1) &&
10268 (comp->steps[comp->steps[op->ch2].ch2].op ==
10269 XPATH_OP_VALUE)) {
10270 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010271
Daniel Veillardf06307e2001-07-03 10:35:50 +000010272 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10273 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10274 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010275
Daniel Veillardf06307e2001-07-03 10:35:50 +000010276 if (val->floatval == (float) indx) {
10277 total +=
10278 xmlXPathNodeCollectAndTestNth(ctxt, op,
10279 indx, NULL,
10280 NULL);
10281 return (total);
10282 }
10283 }
10284 }
10285 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10286 return (total);
10287 }
10288 case XPATH_OP_VALUE:
10289 valuePush(ctxt,
10290 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10291 return (total);
10292 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010293 xmlXPathObjectPtr val;
10294
Daniel Veillardf06307e2001-07-03 10:35:50 +000010295 if (op->ch1 != -1)
10296 total +=
10297 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010298 if (op->value5 == NULL) {
10299 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10300 if (val == NULL) {
10301 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10302 return(0);
10303 }
10304 valuePush(ctxt, val);
10305 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010306 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010307
Daniel Veillardf06307e2001-07-03 10:35:50 +000010308 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10309 if (URI == NULL) {
10310 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010311 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010312 op->value4, op->value5);
10313 return (total);
10314 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010315 val = xmlXPathVariableLookupNS(ctxt->context,
10316 op->value4, URI);
10317 if (val == NULL) {
10318 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10319 return(0);
10320 }
10321 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010322 }
10323 return (total);
10324 }
10325 case XPATH_OP_FUNCTION:{
10326 xmlXPathFunction func;
10327 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010328 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010329
10330 if (op->ch1 != -1)
10331 total +=
10332 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010333 if (ctxt->valueNr < op->value) {
10334 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010335 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010336 ctxt->error = XPATH_INVALID_OPERAND;
10337 return (total);
10338 }
10339 for (i = 0; i < op->value; i++)
10340 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10341 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010342 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010343 ctxt->error = XPATH_INVALID_OPERAND;
10344 return (total);
10345 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010346 if (op->cache != NULL)
10347 func = (xmlXPathFunction) op->cache;
10348 else {
10349 const xmlChar *URI = NULL;
10350
10351 if (op->value5 == NULL)
10352 func =
10353 xmlXPathFunctionLookup(ctxt->context,
10354 op->value4);
10355 else {
10356 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10357 if (URI == NULL) {
10358 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010359 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010360 op->value4, op->value5);
10361 return (total);
10362 }
10363 func = xmlXPathFunctionLookupNS(ctxt->context,
10364 op->value4, URI);
10365 }
10366 if (func == NULL) {
10367 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010368 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010369 op->value4);
10370 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010371 }
10372 op->cache = (void *) func;
10373 op->cacheURI = (void *) URI;
10374 }
10375 oldFunc = ctxt->context->function;
10376 oldFuncURI = ctxt->context->functionURI;
10377 ctxt->context->function = op->value4;
10378 ctxt->context->functionURI = op->cacheURI;
10379 func(ctxt, op->value);
10380 ctxt->context->function = oldFunc;
10381 ctxt->context->functionURI = oldFuncURI;
10382 return (total);
10383 }
10384 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010385 bakd = ctxt->context->doc;
10386 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010387 if (op->ch1 != -1)
10388 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010389 ctxt->context->doc = bakd;
10390 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010391 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010392 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010393 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010394 ctxt->context->doc = bakd;
10395 ctxt->context->node = bak;
10396 CHECK_ERROR0;
10397 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010398 return (total);
10399 case XPATH_OP_PREDICATE:
10400 case XPATH_OP_FILTER:{
10401 xmlXPathObjectPtr res;
10402 xmlXPathObjectPtr obj, tmp;
10403 xmlNodeSetPtr newset = NULL;
10404 xmlNodeSetPtr oldset;
10405 xmlNodePtr oldnode;
10406 int i;
10407
10408 /*
10409 * Optimization for ()[1] selection i.e. the first elem
10410 */
10411 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10412 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10413 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10414 xmlXPathObjectPtr val;
10415
10416 val = comp->steps[op->ch2].value4;
10417 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10418 (val->floatval == 1.0)) {
10419 xmlNodePtr first = NULL;
10420
10421 total +=
10422 xmlXPathCompOpEvalFirst(ctxt,
10423 &comp->steps[op->ch1],
10424 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010425 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010426 /*
10427 * The nodeset should be in document order,
10428 * Keep only the first value
10429 */
10430 if ((ctxt->value != NULL) &&
10431 (ctxt->value->type == XPATH_NODESET) &&
10432 (ctxt->value->nodesetval != NULL) &&
10433 (ctxt->value->nodesetval->nodeNr > 1))
10434 ctxt->value->nodesetval->nodeNr = 1;
10435 return (total);
10436 }
10437 }
10438 /*
10439 * Optimization for ()[last()] selection i.e. the last elem
10440 */
10441 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10442 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10443 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10444 int f = comp->steps[op->ch2].ch1;
10445
10446 if ((f != -1) &&
10447 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10448 (comp->steps[f].value5 == NULL) &&
10449 (comp->steps[f].value == 0) &&
10450 (comp->steps[f].value4 != NULL) &&
10451 (xmlStrEqual
10452 (comp->steps[f].value4, BAD_CAST "last"))) {
10453 xmlNodePtr last = NULL;
10454
10455 total +=
10456 xmlXPathCompOpEvalLast(ctxt,
10457 &comp->steps[op->ch1],
10458 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010459 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010460 /*
10461 * The nodeset should be in document order,
10462 * Keep only the last value
10463 */
10464 if ((ctxt->value != NULL) &&
10465 (ctxt->value->type == XPATH_NODESET) &&
10466 (ctxt->value->nodesetval != NULL) &&
10467 (ctxt->value->nodesetval->nodeTab != NULL) &&
10468 (ctxt->value->nodesetval->nodeNr > 1)) {
10469 ctxt->value->nodesetval->nodeTab[0] =
10470 ctxt->value->nodesetval->nodeTab[ctxt->
10471 value->
10472 nodesetval->
10473 nodeNr -
10474 1];
10475 ctxt->value->nodesetval->nodeNr = 1;
10476 }
10477 return (total);
10478 }
10479 }
10480
10481 if (op->ch1 != -1)
10482 total +=
10483 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010484 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010485 if (op->ch2 == -1)
10486 return (total);
10487 if (ctxt->value == NULL)
10488 return (total);
10489
10490 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010491
10492#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010493 /*
10494 * Hum are we filtering the result of an XPointer expression
10495 */
10496 if (ctxt->value->type == XPATH_LOCATIONSET) {
10497 xmlLocationSetPtr newlocset = NULL;
10498 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010499
Daniel Veillardf06307e2001-07-03 10:35:50 +000010500 /*
10501 * Extract the old locset, and then evaluate the result of the
10502 * expression for all the element in the locset. use it to grow
10503 * up a new locset.
10504 */
10505 CHECK_TYPE0(XPATH_LOCATIONSET);
10506 obj = valuePop(ctxt);
10507 oldlocset = obj->user;
10508 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010509
Daniel Veillardf06307e2001-07-03 10:35:50 +000010510 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10511 ctxt->context->contextSize = 0;
10512 ctxt->context->proximityPosition = 0;
10513 if (op->ch2 != -1)
10514 total +=
10515 xmlXPathCompOpEval(ctxt,
10516 &comp->steps[op->ch2]);
10517 res = valuePop(ctxt);
10518 if (res != NULL)
10519 xmlXPathFreeObject(res);
10520 valuePush(ctxt, obj);
10521 CHECK_ERROR0;
10522 return (total);
10523 }
10524 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010525
Daniel Veillardf06307e2001-07-03 10:35:50 +000010526 for (i = 0; i < oldlocset->locNr; i++) {
10527 /*
10528 * Run the evaluation with a node list made of a
10529 * single item in the nodelocset.
10530 */
10531 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010532 ctxt->context->contextSize = oldlocset->locNr;
10533 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010534 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10535 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010536
Daniel Veillardf06307e2001-07-03 10:35:50 +000010537 if (op->ch2 != -1)
10538 total +=
10539 xmlXPathCompOpEval(ctxt,
10540 &comp->steps[op->ch2]);
10541 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010542
Daniel Veillardf06307e2001-07-03 10:35:50 +000010543 /*
10544 * The result of the evaluation need to be tested to
10545 * decided whether the filter succeeded or not
10546 */
10547 res = valuePop(ctxt);
10548 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10549 xmlXPtrLocationSetAdd(newlocset,
10550 xmlXPathObjectCopy
10551 (oldlocset->locTab[i]));
10552 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010553
Daniel Veillardf06307e2001-07-03 10:35:50 +000010554 /*
10555 * Cleanup
10556 */
10557 if (res != NULL)
10558 xmlXPathFreeObject(res);
10559 if (ctxt->value == tmp) {
10560 res = valuePop(ctxt);
10561 xmlXPathFreeObject(res);
10562 }
10563
10564 ctxt->context->node = NULL;
10565 }
10566
10567 /*
10568 * The result is used as the new evaluation locset.
10569 */
10570 xmlXPathFreeObject(obj);
10571 ctxt->context->node = NULL;
10572 ctxt->context->contextSize = -1;
10573 ctxt->context->proximityPosition = -1;
10574 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10575 ctxt->context->node = oldnode;
10576 return (total);
10577 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010578#endif /* LIBXML_XPTR_ENABLED */
10579
Daniel Veillardf06307e2001-07-03 10:35:50 +000010580 /*
10581 * Extract the old set, and then evaluate the result of the
10582 * expression for all the element in the set. use it to grow
10583 * up a new set.
10584 */
10585 CHECK_TYPE0(XPATH_NODESET);
10586 obj = valuePop(ctxt);
10587 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010588
Daniel Veillardf06307e2001-07-03 10:35:50 +000010589 oldnode = ctxt->context->node;
10590 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010591
Daniel Veillardf06307e2001-07-03 10:35:50 +000010592 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10593 ctxt->context->contextSize = 0;
10594 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000010595/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000010596 if (op->ch2 != -1)
10597 total +=
10598 xmlXPathCompOpEval(ctxt,
10599 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010600 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010601 res = valuePop(ctxt);
10602 if (res != NULL)
10603 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000010604*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000010605 valuePush(ctxt, obj);
10606 ctxt->context->node = oldnode;
10607 CHECK_ERROR0;
10608 } else {
10609 /*
10610 * Initialize the new set.
10611 */
10612 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010613
Daniel Veillardf06307e2001-07-03 10:35:50 +000010614 for (i = 0; i < oldset->nodeNr; i++) {
10615 /*
10616 * Run the evaluation with a node list made of
10617 * a single item in the nodeset.
10618 */
10619 ctxt->context->node = oldset->nodeTab[i];
10620 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10621 valuePush(ctxt, tmp);
10622 ctxt->context->contextSize = oldset->nodeNr;
10623 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010624
Daniel Veillardf06307e2001-07-03 10:35:50 +000010625 if (op->ch2 != -1)
10626 total +=
10627 xmlXPathCompOpEval(ctxt,
10628 &comp->steps[op->ch2]);
10629 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010630
Daniel Veillardf06307e2001-07-03 10:35:50 +000010631 /*
William M. Brack08171912003-12-29 02:52:11 +000010632 * The result of the evaluation needs to be tested to
10633 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010634 */
10635 res = valuePop(ctxt);
10636 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10637 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10638 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010639
Daniel Veillardf06307e2001-07-03 10:35:50 +000010640 /*
10641 * Cleanup
10642 */
10643 if (res != NULL)
10644 xmlXPathFreeObject(res);
10645 if (ctxt->value == tmp) {
10646 res = valuePop(ctxt);
10647 xmlXPathFreeObject(res);
10648 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010649
Daniel Veillardf06307e2001-07-03 10:35:50 +000010650 ctxt->context->node = NULL;
10651 }
10652
10653 /*
10654 * The result is used as the new evaluation set.
10655 */
10656 xmlXPathFreeObject(obj);
10657 ctxt->context->node = NULL;
10658 ctxt->context->contextSize = -1;
10659 ctxt->context->proximityPosition = -1;
10660 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10661 }
10662 ctxt->context->node = oldnode;
10663 return (total);
10664 }
10665 case XPATH_OP_SORT:
10666 if (op->ch1 != -1)
10667 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010668 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010669 if ((ctxt->value != NULL) &&
10670 (ctxt->value->type == XPATH_NODESET) &&
10671 (ctxt->value->nodesetval != NULL))
10672 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10673 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010674#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010675 case XPATH_OP_RANGETO:{
10676 xmlXPathObjectPtr range;
10677 xmlXPathObjectPtr res, obj;
10678 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010679 xmlLocationSetPtr newlocset = NULL;
10680 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010681 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000010682 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010683
Daniel Veillardf06307e2001-07-03 10:35:50 +000010684 if (op->ch1 != -1)
10685 total +=
10686 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10687 if (op->ch2 == -1)
10688 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010689
William M. Brack08171912003-12-29 02:52:11 +000010690 if (ctxt->value->type == XPATH_LOCATIONSET) {
10691 /*
10692 * Extract the old locset, and then evaluate the result of the
10693 * expression for all the element in the locset. use it to grow
10694 * up a new locset.
10695 */
10696 CHECK_TYPE0(XPATH_LOCATIONSET);
10697 obj = valuePop(ctxt);
10698 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010699
William M. Brack08171912003-12-29 02:52:11 +000010700 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000010701 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000010702 ctxt->context->contextSize = 0;
10703 ctxt->context->proximityPosition = 0;
10704 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10705 res = valuePop(ctxt);
10706 if (res != NULL)
10707 xmlXPathFreeObject(res);
10708 valuePush(ctxt, obj);
10709 CHECK_ERROR0;
10710 return (total);
10711 }
10712 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010713
William M. Brack08171912003-12-29 02:52:11 +000010714 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010715 /*
William M. Brack08171912003-12-29 02:52:11 +000010716 * Run the evaluation with a node list made of a
10717 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010718 */
William M. Brackf7eb7942003-12-31 07:59:17 +000010719 ctxt->context->node = oldlocset->locTab[i]->user;
10720 ctxt->context->contextSize = oldlocset->locNr;
10721 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010722 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10723 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010724
Daniel Veillardf06307e2001-07-03 10:35:50 +000010725 if (op->ch2 != -1)
10726 total +=
10727 xmlXPathCompOpEval(ctxt,
10728 &comp->steps[op->ch2]);
10729 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010730
Daniel Veillardf06307e2001-07-03 10:35:50 +000010731 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000010732 if (res->type == XPATH_LOCATIONSET) {
10733 xmlLocationSetPtr rloc =
10734 (xmlLocationSetPtr)res->user;
10735 for (j=0; j<rloc->locNr; j++) {
10736 range = xmlXPtrNewRange(
10737 oldlocset->locTab[i]->user,
10738 oldlocset->locTab[i]->index,
10739 rloc->locTab[j]->user2,
10740 rloc->locTab[j]->index2);
10741 if (range != NULL) {
10742 xmlXPtrLocationSetAdd(newlocset, range);
10743 }
10744 }
10745 } else {
10746 range = xmlXPtrNewRangeNodeObject(
10747 (xmlNodePtr)oldlocset->locTab[i]->user, res);
10748 if (range != NULL) {
10749 xmlXPtrLocationSetAdd(newlocset,range);
10750 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010751 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010752
Daniel Veillardf06307e2001-07-03 10:35:50 +000010753 /*
10754 * Cleanup
10755 */
10756 if (res != NULL)
10757 xmlXPathFreeObject(res);
10758 if (ctxt->value == tmp) {
10759 res = valuePop(ctxt);
10760 xmlXPathFreeObject(res);
10761 }
10762
10763 ctxt->context->node = NULL;
10764 }
William M. Brack72ee48d2003-12-30 08:30:19 +000010765 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000010766 CHECK_TYPE0(XPATH_NODESET);
10767 obj = valuePop(ctxt);
10768 oldset = obj->nodesetval;
10769 ctxt->context->node = NULL;
10770
10771 newlocset = xmlXPtrLocationSetCreate(NULL);
10772
10773 if (oldset != NULL) {
10774 for (i = 0; i < oldset->nodeNr; i++) {
10775 /*
10776 * Run the evaluation with a node list made of a single item
10777 * in the nodeset.
10778 */
10779 ctxt->context->node = oldset->nodeTab[i];
10780 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10781 valuePush(ctxt, tmp);
10782
10783 if (op->ch2 != -1)
10784 total +=
10785 xmlXPathCompOpEval(ctxt,
10786 &comp->steps[op->ch2]);
10787 CHECK_ERROR0;
10788
William M. Brack08171912003-12-29 02:52:11 +000010789 res = valuePop(ctxt);
10790 range =
10791 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10792 res);
10793 if (range != NULL) {
10794 xmlXPtrLocationSetAdd(newlocset, range);
10795 }
10796
10797 /*
10798 * Cleanup
10799 */
10800 if (res != NULL)
10801 xmlXPathFreeObject(res);
10802 if (ctxt->value == tmp) {
10803 res = valuePop(ctxt);
10804 xmlXPathFreeObject(res);
10805 }
10806
10807 ctxt->context->node = NULL;
10808 }
10809 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010810 }
10811
10812 /*
10813 * The result is used as the new evaluation set.
10814 */
10815 xmlXPathFreeObject(obj);
10816 ctxt->context->node = NULL;
10817 ctxt->context->contextSize = -1;
10818 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010819 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010820 return (total);
10821 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010822#endif /* LIBXML_XPTR_ENABLED */
10823 }
10824 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010825 "XPath: unknown precompiled operation %d\n", op->op);
10826 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010827}
10828
10829/**
10830 * xmlXPathRunEval:
10831 * @ctxt: the XPath parser context with the compiled expression
10832 *
10833 * Evaluate the Precompiled XPath expression in the given context.
10834 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010835static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010836xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10837 xmlXPathCompExprPtr comp;
10838
10839 if ((ctxt == NULL) || (ctxt->comp == NULL))
10840 return;
10841
10842 if (ctxt->valueTab == NULL) {
10843 /* Allocate the value stack */
10844 ctxt->valueTab = (xmlXPathObjectPtr *)
10845 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10846 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010847 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010848 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010849 }
10850 ctxt->valueNr = 0;
10851 ctxt->valueMax = 10;
10852 ctxt->value = NULL;
10853 }
10854 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010855 if(comp->last < 0) {
10856 xmlGenericError(xmlGenericErrorContext,
10857 "xmlXPathRunEval: last is less than zero\n");
10858 return;
10859 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010860 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10861}
10862
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010863/************************************************************************
10864 * *
10865 * Public interfaces *
10866 * *
10867 ************************************************************************/
10868
10869/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010870 * xmlXPathEvalPredicate:
10871 * @ctxt: the XPath context
10872 * @res: the Predicate Expression evaluation result
10873 *
10874 * Evaluate a predicate result for the current node.
10875 * A PredicateExpr is evaluated by evaluating the Expr and converting
10876 * the result to a boolean. If the result is a number, the result will
10877 * be converted to true if the number is equal to the position of the
10878 * context node in the context node list (as returned by the position
10879 * function) and will be converted to false otherwise; if the result
10880 * is not a number, then the result will be converted as if by a call
10881 * to the boolean function.
10882 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010883 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010884 */
10885int
10886xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10887 if (res == NULL) return(0);
10888 switch (res->type) {
10889 case XPATH_BOOLEAN:
10890 return(res->boolval);
10891 case XPATH_NUMBER:
10892 return(res->floatval == ctxt->proximityPosition);
10893 case XPATH_NODESET:
10894 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010895 if (res->nodesetval == NULL)
10896 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010897 return(res->nodesetval->nodeNr != 0);
10898 case XPATH_STRING:
10899 return((res->stringval != NULL) &&
10900 (xmlStrlen(res->stringval) != 0));
10901 default:
10902 STRANGE
10903 }
10904 return(0);
10905}
10906
10907/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010908 * xmlXPathEvaluatePredicateResult:
10909 * @ctxt: the XPath Parser context
10910 * @res: the Predicate Expression evaluation result
10911 *
10912 * Evaluate a predicate result for the current node.
10913 * A PredicateExpr is evaluated by evaluating the Expr and converting
10914 * the result to a boolean. If the result is a number, the result will
10915 * be converted to true if the number is equal to the position of the
10916 * context node in the context node list (as returned by the position
10917 * function) and will be converted to false otherwise; if the result
10918 * is not a number, then the result will be converted as if by a call
10919 * to the boolean function.
10920 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010921 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010922 */
10923int
10924xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10925 xmlXPathObjectPtr res) {
10926 if (res == NULL) return(0);
10927 switch (res->type) {
10928 case XPATH_BOOLEAN:
10929 return(res->boolval);
10930 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000010931#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000010932 return((res->floatval == ctxt->context->proximityPosition) &&
10933 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000010934#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010935 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000010936#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010937 case XPATH_NODESET:
10938 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010939 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010940 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010941 return(res->nodesetval->nodeNr != 0);
10942 case XPATH_STRING:
10943 return((res->stringval != NULL) &&
10944 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000010945#ifdef LIBXML_XPTR_ENABLED
10946 case XPATH_LOCATIONSET:{
10947 xmlLocationSetPtr ptr = res->user;
10948 if (ptr == NULL)
10949 return(0);
10950 return (ptr->locNr != 0);
10951 }
10952#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010953 default:
10954 STRANGE
10955 }
10956 return(0);
10957}
10958
10959/**
Daniel Veillard4773df22004-01-23 13:15:13 +000010960 * xmlXPathCtxtCompile:
10961 * @ctxt: an XPath context
10962 * @str: the XPath expression
10963 *
10964 * Compile an XPath expression
10965 *
10966 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
10967 * the caller has to free the object.
10968 */
10969xmlXPathCompExprPtr
10970xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
10971 xmlXPathParserContextPtr pctxt;
10972 xmlXPathCompExprPtr comp;
10973
10974 xmlXPathInit();
10975
10976 pctxt = xmlXPathNewParserContext(str, ctxt);
10977 xmlXPathCompileExpr(pctxt);
10978
10979 if( pctxt->error != XPATH_EXPRESSION_OK )
10980 {
10981 xmlXPathFreeParserContext(pctxt);
10982 return (0);
10983 }
10984
10985 if (*pctxt->cur != 0) {
10986 /*
10987 * aleksey: in some cases this line prints *second* error message
10988 * (see bug #78858) and probably this should be fixed.
10989 * However, we are not sure that all error messages are printed
10990 * out in other places. It's not critical so we leave it as-is for now
10991 */
10992 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10993 comp = NULL;
10994 } else {
10995 comp = pctxt->comp;
10996 pctxt->comp = NULL;
10997 }
10998 xmlXPathFreeParserContext(pctxt);
10999 if (comp != NULL) {
11000 comp->expr = xmlStrdup(str);
11001#ifdef DEBUG_EVAL_COUNTS
11002 comp->string = xmlStrdup(str);
11003 comp->nb = 0;
11004#endif
11005 }
11006 return(comp);
11007}
11008
11009/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011010 * xmlXPathCompile:
11011 * @str: the XPath expression
11012 *
11013 * Compile an XPath expression
11014 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000011015 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011016 * the caller has to free the object.
11017 */
11018xmlXPathCompExprPtr
11019xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000011020 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011021}
11022
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011023/**
11024 * xmlXPathCompiledEval:
11025 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000011026 * @ctx: the XPath context
11027 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011028 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000011029 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011030 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000011031 * the caller has to free the object.
11032 */
11033xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011034xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000011035 xmlXPathParserContextPtr ctxt;
11036 xmlXPathObjectPtr res, tmp, init = NULL;
11037 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000011038#ifndef LIBXML_THREAD_ENABLED
11039 static int reentance = 0;
11040#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011041
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011042 if ((comp == NULL) || (ctx == NULL))
11043 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011044 xmlXPathInit();
11045
11046 CHECK_CONTEXT(ctx)
11047
Daniel Veillard81463942001-10-16 12:34:39 +000011048#ifndef LIBXML_THREAD_ENABLED
11049 reentance++;
11050 if (reentance > 1)
11051 xmlXPathDisableOptimizer = 1;
11052#endif
11053
Daniel Veillardf06307e2001-07-03 10:35:50 +000011054#ifdef DEBUG_EVAL_COUNTS
11055 comp->nb++;
11056 if ((comp->string != NULL) && (comp->nb > 100)) {
11057 fprintf(stderr, "100 x %s\n", comp->string);
11058 comp->nb = 0;
11059 }
11060#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011061 ctxt = xmlXPathCompParserContext(comp, ctx);
11062 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011063
11064 if (ctxt->value == NULL) {
11065 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011066 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011067 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011068 } else {
11069 res = valuePop(ctxt);
11070 }
11071
Daniel Veillardf06307e2001-07-03 10:35:50 +000011072
Owen Taylor3473f882001-02-23 17:55:21 +000011073 do {
11074 tmp = valuePop(ctxt);
11075 if (tmp != NULL) {
11076 if (tmp != init)
11077 stack++;
11078 xmlXPathFreeObject(tmp);
11079 }
11080 } while (tmp != NULL);
11081 if ((stack != 0) && (res != NULL)) {
11082 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011083 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011084 stack);
11085 }
11086 if (ctxt->error != XPATH_EXPRESSION_OK) {
11087 xmlXPathFreeObject(res);
11088 res = NULL;
11089 }
11090
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011091
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011092 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011093 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011094#ifndef LIBXML_THREAD_ENABLED
11095 reentance--;
11096#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011097 return(res);
11098}
11099
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011100/**
11101 * xmlXPathEvalExpr:
11102 * @ctxt: the XPath Parser context
11103 *
11104 * Parse and evaluate an XPath expression in the given context,
11105 * then push the result on the context stack
11106 */
11107void
11108xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
11109 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011110 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011111 xmlXPathRunEval(ctxt);
11112}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011113
11114/**
11115 * xmlXPathEval:
11116 * @str: the XPath expression
11117 * @ctx: the XPath context
11118 *
11119 * Evaluate the XPath Location Path in the given context.
11120 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011121 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011122 * the caller has to free the object.
11123 */
11124xmlXPathObjectPtr
11125xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11126 xmlXPathParserContextPtr ctxt;
11127 xmlXPathObjectPtr res, tmp, init = NULL;
11128 int stack = 0;
11129
11130 xmlXPathInit();
11131
11132 CHECK_CONTEXT(ctx)
11133
11134 ctxt = xmlXPathNewParserContext(str, ctx);
11135 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011136
11137 if (ctxt->value == NULL) {
11138 xmlGenericError(xmlGenericErrorContext,
11139 "xmlXPathEval: evaluation failed\n");
11140 res = NULL;
11141 } else if (*ctxt->cur != 0) {
11142 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11143 res = NULL;
11144 } else {
11145 res = valuePop(ctxt);
11146 }
11147
11148 do {
11149 tmp = valuePop(ctxt);
11150 if (tmp != NULL) {
11151 if (tmp != init)
11152 stack++;
11153 xmlXPathFreeObject(tmp);
11154 }
11155 } while (tmp != NULL);
11156 if ((stack != 0) && (res != NULL)) {
11157 xmlGenericError(xmlGenericErrorContext,
11158 "xmlXPathEval: %d object left on the stack\n",
11159 stack);
11160 }
11161 if (ctxt->error != XPATH_EXPRESSION_OK) {
11162 xmlXPathFreeObject(res);
11163 res = NULL;
11164 }
11165
Owen Taylor3473f882001-02-23 17:55:21 +000011166 xmlXPathFreeParserContext(ctxt);
11167 return(res);
11168}
11169
11170/**
11171 * xmlXPathEvalExpression:
11172 * @str: the XPath expression
11173 * @ctxt: the XPath context
11174 *
11175 * Evaluate the XPath expression in the given context.
11176 *
11177 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11178 * the caller has to free the object.
11179 */
11180xmlXPathObjectPtr
11181xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11182 xmlXPathParserContextPtr pctxt;
11183 xmlXPathObjectPtr res, tmp;
11184 int stack = 0;
11185
11186 xmlXPathInit();
11187
11188 CHECK_CONTEXT(ctxt)
11189
11190 pctxt = xmlXPathNewParserContext(str, ctxt);
11191 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011192
11193 if (*pctxt->cur != 0) {
11194 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11195 res = NULL;
11196 } else {
11197 res = valuePop(pctxt);
11198 }
11199 do {
11200 tmp = valuePop(pctxt);
11201 if (tmp != NULL) {
11202 xmlXPathFreeObject(tmp);
11203 stack++;
11204 }
11205 } while (tmp != NULL);
11206 if ((stack != 0) && (res != NULL)) {
11207 xmlGenericError(xmlGenericErrorContext,
11208 "xmlXPathEvalExpression: %d object left on the stack\n",
11209 stack);
11210 }
11211 xmlXPathFreeParserContext(pctxt);
11212 return(res);
11213}
11214
Daniel Veillard42766c02002-08-22 20:52:17 +000011215/************************************************************************
11216 * *
11217 * Extra functions not pertaining to the XPath spec *
11218 * *
11219 ************************************************************************/
11220/**
11221 * xmlXPathEscapeUriFunction:
11222 * @ctxt: the XPath Parser context
11223 * @nargs: the number of arguments
11224 *
11225 * Implement the escape-uri() XPath function
11226 * string escape-uri(string $str, bool $escape-reserved)
11227 *
11228 * This function applies the URI escaping rules defined in section 2 of [RFC
11229 * 2396] to the string supplied as $uri-part, which typically represents all
11230 * or part of a URI. The effect of the function is to replace any special
11231 * character in the string by an escape sequence of the form %xx%yy...,
11232 * where xxyy... is the hexadecimal representation of the octets used to
11233 * represent the character in UTF-8.
11234 *
11235 * The set of characters that are escaped depends on the setting of the
11236 * boolean argument $escape-reserved.
11237 *
11238 * If $escape-reserved is true, all characters are escaped other than lower
11239 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11240 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11241 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11242 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11243 * A-F).
11244 *
11245 * If $escape-reserved is false, the behavior differs in that characters
11246 * referred to in [RFC 2396] as reserved characters are not escaped. These
11247 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11248 *
11249 * [RFC 2396] does not define whether escaped URIs should use lower case or
11250 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11251 * compared using string comparison functions, this function must always use
11252 * the upper-case letters A-F.
11253 *
11254 * Generally, $escape-reserved should be set to true when escaping a string
11255 * that is to form a single part of a URI, and to false when escaping an
11256 * entire URI or URI reference.
11257 *
11258 * In the case of non-ascii characters, the string is encoded according to
11259 * utf-8 and then converted according to RFC 2396.
11260 *
11261 * Examples
11262 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11263 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11264 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11265 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11266 *
11267 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011268static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011269xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11270 xmlXPathObjectPtr str;
11271 int escape_reserved;
11272 xmlBufferPtr target;
11273 xmlChar *cptr;
11274 xmlChar escape[4];
11275
11276 CHECK_ARITY(2);
11277
11278 escape_reserved = xmlXPathPopBoolean(ctxt);
11279
11280 CAST_TO_STRING;
11281 str = valuePop(ctxt);
11282
11283 target = xmlBufferCreate();
11284
11285 escape[0] = '%';
11286 escape[3] = 0;
11287
11288 if (target) {
11289 for (cptr = str->stringval; *cptr; cptr++) {
11290 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11291 (*cptr >= 'a' && *cptr <= 'z') ||
11292 (*cptr >= '0' && *cptr <= '9') ||
11293 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11294 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11295 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11296 (*cptr == '%' &&
11297 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11298 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11299 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11300 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11301 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11302 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11303 (!escape_reserved &&
11304 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11305 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11306 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11307 *cptr == ','))) {
11308 xmlBufferAdd(target, cptr, 1);
11309 } else {
11310 if ((*cptr >> 4) < 10)
11311 escape[1] = '0' + (*cptr >> 4);
11312 else
11313 escape[1] = 'A' - 10 + (*cptr >> 4);
11314 if ((*cptr & 0xF) < 10)
11315 escape[2] = '0' + (*cptr & 0xF);
11316 else
11317 escape[2] = 'A' - 10 + (*cptr & 0xF);
11318
11319 xmlBufferAdd(target, &escape[0], 3);
11320 }
11321 }
11322 }
11323 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11324 xmlBufferFree(target);
11325 xmlXPathFreeObject(str);
11326}
11327
Owen Taylor3473f882001-02-23 17:55:21 +000011328/**
11329 * xmlXPathRegisterAllFunctions:
11330 * @ctxt: the XPath context
11331 *
11332 * Registers all default XPath functions in this context
11333 */
11334void
11335xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11336{
11337 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11338 xmlXPathBooleanFunction);
11339 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11340 xmlXPathCeilingFunction);
11341 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11342 xmlXPathCountFunction);
11343 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11344 xmlXPathConcatFunction);
11345 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11346 xmlXPathContainsFunction);
11347 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11348 xmlXPathIdFunction);
11349 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11350 xmlXPathFalseFunction);
11351 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11352 xmlXPathFloorFunction);
11353 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11354 xmlXPathLastFunction);
11355 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11356 xmlXPathLangFunction);
11357 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11358 xmlXPathLocalNameFunction);
11359 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11360 xmlXPathNotFunction);
11361 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11362 xmlXPathNameFunction);
11363 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11364 xmlXPathNamespaceURIFunction);
11365 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11366 xmlXPathNormalizeFunction);
11367 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11368 xmlXPathNumberFunction);
11369 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11370 xmlXPathPositionFunction);
11371 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11372 xmlXPathRoundFunction);
11373 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11374 xmlXPathStringFunction);
11375 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11376 xmlXPathStringLengthFunction);
11377 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11378 xmlXPathStartsWithFunction);
11379 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11380 xmlXPathSubstringFunction);
11381 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11382 xmlXPathSubstringBeforeFunction);
11383 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11384 xmlXPathSubstringAfterFunction);
11385 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11386 xmlXPathSumFunction);
11387 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11388 xmlXPathTrueFunction);
11389 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11390 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011391
11392 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11393 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11394 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011395}
11396
11397#endif /* LIBXML_XPATH_ENABLED */