blob: c42e0092e60217e70cbe5f8b748fcc504802b0f2 [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) {
565 comp->steps[comp->nbStep].value4 =
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) {
571 comp->steps[comp->nbStep].value5 =
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 */
1619 if (node1 == node2->next)
1620 return(-1);
1621 for (cur = node1->next;cur != NULL;cur = cur->next)
1622 if (cur == node2)
1623 return(1);
1624 return(-1); /* assume there is no sibling list corruption */
1625}
1626
1627/**
1628 * xmlXPathNodeSetSort:
1629 * @set: the node set
1630 *
1631 * Sort the node set in document order
1632 */
1633void
1634xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001635 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001636 xmlNodePtr tmp;
1637
1638 if (set == NULL)
1639 return;
1640
1641 /* Use Shell's sort to sort the node-set */
1642 len = set->nodeNr;
1643 for (incr = len / 2; incr > 0; incr /= 2) {
1644 for (i = incr; i < len; i++) {
1645 j = i - incr;
1646 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001647 if (xmlXPathCmpNodes(set->nodeTab[j],
1648 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001649 tmp = set->nodeTab[j];
1650 set->nodeTab[j] = set->nodeTab[j + incr];
1651 set->nodeTab[j + incr] = tmp;
1652 j -= incr;
1653 } else
1654 break;
1655 }
1656 }
1657 }
1658}
1659
1660#define XML_NODESET_DEFAULT 10
1661/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001662 * xmlXPathNodeSetDupNs:
1663 * @node: the parent node of the namespace XPath node
1664 * @ns: the libxml namespace declaration node.
1665 *
1666 * Namespace node in libxml don't match the XPath semantic. In a node set
1667 * the namespace nodes are duplicated and the next pointer is set to the
1668 * parent node in the XPath semantic.
1669 *
1670 * Returns the newly created object.
1671 */
1672static xmlNodePtr
1673xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1674 xmlNsPtr cur;
1675
1676 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1677 return(NULL);
1678 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1679 return((xmlNodePtr) ns);
1680
1681 /*
1682 * Allocate a new Namespace and fill the fields.
1683 */
1684 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1685 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001686 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001687 return(NULL);
1688 }
1689 memset(cur, 0, sizeof(xmlNs));
1690 cur->type = XML_NAMESPACE_DECL;
1691 if (ns->href != NULL)
1692 cur->href = xmlStrdup(ns->href);
1693 if (ns->prefix != NULL)
1694 cur->prefix = xmlStrdup(ns->prefix);
1695 cur->next = (xmlNsPtr) node;
1696 return((xmlNodePtr) cur);
1697}
1698
1699/**
1700 * xmlXPathNodeSetFreeNs:
1701 * @ns: the XPath namespace node found in a nodeset.
1702 *
William M. Brack08171912003-12-29 02:52:11 +00001703 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001704 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00001705 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001706 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001707void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001708xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1709 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1710 return;
1711
1712 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1713 if (ns->href != NULL)
1714 xmlFree((xmlChar *)ns->href);
1715 if (ns->prefix != NULL)
1716 xmlFree((xmlChar *)ns->prefix);
1717 xmlFree(ns);
1718 }
1719}
1720
1721/**
Owen Taylor3473f882001-02-23 17:55:21 +00001722 * xmlXPathNodeSetCreate:
1723 * @val: an initial xmlNodePtr, or NULL
1724 *
1725 * Create a new xmlNodeSetPtr of type double and of value @val
1726 *
1727 * Returns the newly created object.
1728 */
1729xmlNodeSetPtr
1730xmlXPathNodeSetCreate(xmlNodePtr val) {
1731 xmlNodeSetPtr ret;
1732
1733 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1734 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001735 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001736 return(NULL);
1737 }
1738 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1739 if (val != NULL) {
1740 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1741 sizeof(xmlNodePtr));
1742 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001743 xmlXPathErrMemory(NULL, "creating nodeset\n");
1744 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001745 return(NULL);
1746 }
1747 memset(ret->nodeTab, 0 ,
1748 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1749 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001750 if (val->type == XML_NAMESPACE_DECL) {
1751 xmlNsPtr ns = (xmlNsPtr) val;
1752
1753 ret->nodeTab[ret->nodeNr++] =
1754 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1755 } else
1756 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001757 }
1758 return(ret);
1759}
1760
1761/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001762 * xmlXPathNodeSetContains:
1763 * @cur: the node-set
1764 * @val: the node
1765 *
1766 * checks whether @cur contains @val
1767 *
1768 * Returns true (1) if @cur contains @val, false (0) otherwise
1769 */
1770int
1771xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1772 int i;
1773
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001774 if (val->type == XML_NAMESPACE_DECL) {
1775 for (i = 0; i < cur->nodeNr; i++) {
1776 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1777 xmlNsPtr ns1, ns2;
1778
1779 ns1 = (xmlNsPtr) val;
1780 ns2 = (xmlNsPtr) cur->nodeTab[i];
1781 if (ns1 == ns2)
1782 return(1);
1783 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1784 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1785 return(1);
1786 }
1787 }
1788 } else {
1789 for (i = 0; i < cur->nodeNr; i++) {
1790 if (cur->nodeTab[i] == val)
1791 return(1);
1792 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001793 }
1794 return(0);
1795}
1796
1797/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001798 * xmlXPathNodeSetAddNs:
1799 * @cur: the initial node set
1800 * @node: the hosting node
1801 * @ns: a the namespace node
1802 *
1803 * add a new namespace node to an existing NodeSet
1804 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001805void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001806xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1807 int i;
1808
1809 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1810 (node->type != XML_ELEMENT_NODE))
1811 return;
1812
William M. Brack08171912003-12-29 02:52:11 +00001813 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001814 /*
William M. Brack08171912003-12-29 02:52:11 +00001815 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001816 */
1817 for (i = 0;i < cur->nodeNr;i++) {
1818 if ((cur->nodeTab[i] != NULL) &&
1819 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001820 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001821 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1822 return;
1823 }
1824
1825 /*
1826 * grow the nodeTab if needed
1827 */
1828 if (cur->nodeMax == 0) {
1829 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1830 sizeof(xmlNodePtr));
1831 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001832 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001833 return;
1834 }
1835 memset(cur->nodeTab, 0 ,
1836 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1837 cur->nodeMax = XML_NODESET_DEFAULT;
1838 } else if (cur->nodeNr == cur->nodeMax) {
1839 xmlNodePtr *temp;
1840
1841 cur->nodeMax *= 2;
1842 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1843 sizeof(xmlNodePtr));
1844 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001845 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001846 return;
1847 }
1848 cur->nodeTab = temp;
1849 }
1850 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1851}
1852
1853/**
Owen Taylor3473f882001-02-23 17:55:21 +00001854 * xmlXPathNodeSetAdd:
1855 * @cur: the initial node set
1856 * @val: a new xmlNodePtr
1857 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001858 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001859 */
1860void
1861xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1862 int i;
1863
1864 if (val == NULL) return;
1865
Daniel Veillardef0b4502003-03-24 13:57:34 +00001866#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001867 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1868 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001869#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001870
William M. Brack08171912003-12-29 02:52:11 +00001871 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001872 /*
William M. Brack08171912003-12-29 02:52:11 +00001873 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00001874 */
1875 for (i = 0;i < cur->nodeNr;i++)
1876 if (cur->nodeTab[i] == val) return;
1877
1878 /*
1879 * grow the nodeTab if needed
1880 */
1881 if (cur->nodeMax == 0) {
1882 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1883 sizeof(xmlNodePtr));
1884 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001885 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001886 return;
1887 }
1888 memset(cur->nodeTab, 0 ,
1889 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1890 cur->nodeMax = XML_NODESET_DEFAULT;
1891 } else if (cur->nodeNr == cur->nodeMax) {
1892 xmlNodePtr *temp;
1893
1894 cur->nodeMax *= 2;
1895 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1896 sizeof(xmlNodePtr));
1897 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001898 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001899 return;
1900 }
1901 cur->nodeTab = temp;
1902 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001903 if (val->type == XML_NAMESPACE_DECL) {
1904 xmlNsPtr ns = (xmlNsPtr) val;
1905
1906 cur->nodeTab[cur->nodeNr++] =
1907 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1908 } else
1909 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001910}
1911
1912/**
1913 * xmlXPathNodeSetAddUnique:
1914 * @cur: the initial node set
1915 * @val: a new xmlNodePtr
1916 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001917 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001918 * when we are sure the node is not already in the set.
1919 */
1920void
1921xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1922 if (val == NULL) return;
1923
Daniel Veillardef0b4502003-03-24 13:57:34 +00001924#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001925 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1926 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001927#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001928
William M. Brack08171912003-12-29 02:52:11 +00001929 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001930 /*
1931 * grow the nodeTab if needed
1932 */
1933 if (cur->nodeMax == 0) {
1934 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1935 sizeof(xmlNodePtr));
1936 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001937 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001938 return;
1939 }
1940 memset(cur->nodeTab, 0 ,
1941 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1942 cur->nodeMax = XML_NODESET_DEFAULT;
1943 } else if (cur->nodeNr == cur->nodeMax) {
1944 xmlNodePtr *temp;
1945
1946 cur->nodeMax *= 2;
1947 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1948 sizeof(xmlNodePtr));
1949 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001950 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001951 return;
1952 }
1953 cur->nodeTab = temp;
1954 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001955 if (val->type == XML_NAMESPACE_DECL) {
1956 xmlNsPtr ns = (xmlNsPtr) val;
1957
1958 cur->nodeTab[cur->nodeNr++] =
1959 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1960 } else
1961 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001962}
1963
1964/**
1965 * xmlXPathNodeSetMerge:
1966 * @val1: the first NodeSet or NULL
1967 * @val2: the second NodeSet
1968 *
1969 * Merges two nodesets, all nodes from @val2 are added to @val1
1970 * if @val1 is NULL, a new set is created and copied from @val2
1971 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001972 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001973 */
1974xmlNodeSetPtr
1975xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001976 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001977
1978 if (val2 == NULL) return(val1);
1979 if (val1 == NULL) {
1980 val1 = xmlXPathNodeSetCreate(NULL);
1981 }
1982
William M. Brack08171912003-12-29 02:52:11 +00001983 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001984 initNr = val1->nodeNr;
1985
1986 for (i = 0;i < val2->nodeNr;i++) {
1987 /*
William M. Brack08171912003-12-29 02:52:11 +00001988 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00001989 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001990 skip = 0;
1991 for (j = 0; j < initNr; j++) {
1992 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1993 skip = 1;
1994 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001995 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1996 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1997 xmlNsPtr ns1, ns2;
1998 ns1 = (xmlNsPtr) val1->nodeTab[j];
1999 ns2 = (xmlNsPtr) val2->nodeTab[i];
2000 if ((ns1->next == ns2->next) &&
2001 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
2002 skip = 1;
2003 break;
2004 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002005 }
2006 }
2007 if (skip)
2008 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00002009
2010 /*
2011 * grow the nodeTab if needed
2012 */
2013 if (val1->nodeMax == 0) {
2014 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2015 sizeof(xmlNodePtr));
2016 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002017 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002018 return(NULL);
2019 }
2020 memset(val1->nodeTab, 0 ,
2021 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2022 val1->nodeMax = XML_NODESET_DEFAULT;
2023 } else if (val1->nodeNr == val1->nodeMax) {
2024 xmlNodePtr *temp;
2025
2026 val1->nodeMax *= 2;
2027 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2028 sizeof(xmlNodePtr));
2029 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002030 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002031 return(NULL);
2032 }
2033 val1->nodeTab = temp;
2034 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002035 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2036 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2037
2038 val1->nodeTab[val1->nodeNr++] =
2039 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2040 } else
2041 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002042 }
2043
2044 return(val1);
2045}
2046
2047/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002048 * xmlXPathNodeSetMergeUnique:
2049 * @val1: the first NodeSet or NULL
2050 * @val2: the second NodeSet
2051 *
2052 * Merges two nodesets, all nodes from @val2 are added to @val1
2053 * if @val1 is NULL, a new set is created and copied from @val2
2054 *
2055 * Returns @val1 once extended or NULL in case of error.
2056 */
2057static xmlNodeSetPtr
2058xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002059 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002060
2061 if (val2 == NULL) return(val1);
2062 if (val1 == NULL) {
2063 val1 = xmlXPathNodeSetCreate(NULL);
2064 }
2065
William M. Brack08171912003-12-29 02:52:11 +00002066 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002067
2068 for (i = 0;i < val2->nodeNr;i++) {
2069 /*
2070 * grow the nodeTab if needed
2071 */
2072 if (val1->nodeMax == 0) {
2073 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2074 sizeof(xmlNodePtr));
2075 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002076 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002077 return(NULL);
2078 }
2079 memset(val1->nodeTab, 0 ,
2080 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2081 val1->nodeMax = XML_NODESET_DEFAULT;
2082 } else if (val1->nodeNr == val1->nodeMax) {
2083 xmlNodePtr *temp;
2084
2085 val1->nodeMax *= 2;
2086 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2087 sizeof(xmlNodePtr));
2088 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002089 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002090 return(NULL);
2091 }
2092 val1->nodeTab = temp;
2093 }
2094 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2095 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2096
2097 val1->nodeTab[val1->nodeNr++] =
2098 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2099 } else
2100 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2101 }
2102
2103 return(val1);
2104}
2105
2106/**
Owen Taylor3473f882001-02-23 17:55:21 +00002107 * xmlXPathNodeSetDel:
2108 * @cur: the initial node set
2109 * @val: an xmlNodePtr
2110 *
2111 * Removes an xmlNodePtr from an existing NodeSet
2112 */
2113void
2114xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2115 int i;
2116
2117 if (cur == NULL) return;
2118 if (val == NULL) return;
2119
2120 /*
William M. Brack08171912003-12-29 02:52:11 +00002121 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002122 */
2123 for (i = 0;i < cur->nodeNr;i++)
2124 if (cur->nodeTab[i] == val) break;
2125
William M. Brack08171912003-12-29 02:52:11 +00002126 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002127#ifdef DEBUG
2128 xmlGenericError(xmlGenericErrorContext,
2129 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2130 val->name);
2131#endif
2132 return;
2133 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002134 if ((cur->nodeTab[i] != NULL) &&
2135 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2136 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002137 cur->nodeNr--;
2138 for (;i < cur->nodeNr;i++)
2139 cur->nodeTab[i] = cur->nodeTab[i + 1];
2140 cur->nodeTab[cur->nodeNr] = NULL;
2141}
2142
2143/**
2144 * xmlXPathNodeSetRemove:
2145 * @cur: the initial node set
2146 * @val: the index to remove
2147 *
2148 * Removes an entry from an existing NodeSet list.
2149 */
2150void
2151xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2152 if (cur == NULL) return;
2153 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002154 if ((cur->nodeTab[val] != NULL) &&
2155 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2156 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002157 cur->nodeNr--;
2158 for (;val < cur->nodeNr;val++)
2159 cur->nodeTab[val] = cur->nodeTab[val + 1];
2160 cur->nodeTab[cur->nodeNr] = NULL;
2161}
2162
2163/**
2164 * xmlXPathFreeNodeSet:
2165 * @obj: the xmlNodeSetPtr to free
2166 *
2167 * Free the NodeSet compound (not the actual nodes !).
2168 */
2169void
2170xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2171 if (obj == NULL) return;
2172 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002173 int i;
2174
William M. Brack08171912003-12-29 02:52:11 +00002175 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002176 for (i = 0;i < obj->nodeNr;i++)
2177 if ((obj->nodeTab[i] != NULL) &&
2178 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2179 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002180 xmlFree(obj->nodeTab);
2181 }
Owen Taylor3473f882001-02-23 17:55:21 +00002182 xmlFree(obj);
2183}
2184
2185/**
2186 * xmlXPathFreeValueTree:
2187 * @obj: the xmlNodeSetPtr to free
2188 *
2189 * Free the NodeSet compound and the actual tree, this is different
2190 * from xmlXPathFreeNodeSet()
2191 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002192static void
Owen Taylor3473f882001-02-23 17:55:21 +00002193xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2194 int i;
2195
2196 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002197
2198 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002199 for (i = 0;i < obj->nodeNr;i++) {
2200 if (obj->nodeTab[i] != NULL) {
2201 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2202 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2203 } else {
2204 xmlFreeNodeList(obj->nodeTab[i]);
2205 }
2206 }
2207 }
Owen Taylor3473f882001-02-23 17:55:21 +00002208 xmlFree(obj->nodeTab);
2209 }
Owen Taylor3473f882001-02-23 17:55:21 +00002210 xmlFree(obj);
2211}
2212
2213#if defined(DEBUG) || defined(DEBUG_STEP)
2214/**
2215 * xmlGenericErrorContextNodeSet:
2216 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002217 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002218 *
2219 * Quick display of a NodeSet
2220 */
2221void
2222xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2223 int i;
2224
2225 if (output == NULL) output = xmlGenericErrorContext;
2226 if (obj == NULL) {
2227 fprintf(output, "NodeSet == NULL !\n");
2228 return;
2229 }
2230 if (obj->nodeNr == 0) {
2231 fprintf(output, "NodeSet is empty\n");
2232 return;
2233 }
2234 if (obj->nodeTab == NULL) {
2235 fprintf(output, " nodeTab == NULL !\n");
2236 return;
2237 }
2238 for (i = 0; i < obj->nodeNr; i++) {
2239 if (obj->nodeTab[i] == NULL) {
2240 fprintf(output, " NULL !\n");
2241 return;
2242 }
2243 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2244 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2245 fprintf(output, " /");
2246 else if (obj->nodeTab[i]->name == NULL)
2247 fprintf(output, " noname!");
2248 else fprintf(output, " %s", obj->nodeTab[i]->name);
2249 }
2250 fprintf(output, "\n");
2251}
2252#endif
2253
2254/**
2255 * xmlXPathNewNodeSet:
2256 * @val: the NodePtr value
2257 *
2258 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2259 * it with the single Node @val
2260 *
2261 * Returns the newly created object.
2262 */
2263xmlXPathObjectPtr
2264xmlXPathNewNodeSet(xmlNodePtr val) {
2265 xmlXPathObjectPtr ret;
2266
2267 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2268 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002269 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002270 return(NULL);
2271 }
2272 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2273 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002274 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002275 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002276 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002277 return(ret);
2278}
2279
2280/**
2281 * xmlXPathNewValueTree:
2282 * @val: the NodePtr value
2283 *
2284 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2285 * it with the tree root @val
2286 *
2287 * Returns the newly created object.
2288 */
2289xmlXPathObjectPtr
2290xmlXPathNewValueTree(xmlNodePtr val) {
2291 xmlXPathObjectPtr ret;
2292
2293 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2294 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002295 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002296 return(NULL);
2297 }
2298 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2299 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002300 ret->boolval = 1;
2301 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002302 ret->nodesetval = xmlXPathNodeSetCreate(val);
2303 return(ret);
2304}
2305
2306/**
2307 * xmlXPathNewNodeSetList:
2308 * @val: an existing NodeSet
2309 *
2310 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2311 * it with the Nodeset @val
2312 *
2313 * Returns the newly created object.
2314 */
2315xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002316xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2317{
Owen Taylor3473f882001-02-23 17:55:21 +00002318 xmlXPathObjectPtr ret;
2319 int i;
2320
2321 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002322 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002323 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002324 ret = xmlXPathNewNodeSet(NULL);
2325 else {
2326 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2327 for (i = 1; i < val->nodeNr; ++i)
2328 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2329 }
Owen Taylor3473f882001-02-23 17:55:21 +00002330
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002331 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002332}
2333
2334/**
2335 * xmlXPathWrapNodeSet:
2336 * @val: the NodePtr value
2337 *
2338 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2339 *
2340 * Returns the newly created object.
2341 */
2342xmlXPathObjectPtr
2343xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2344 xmlXPathObjectPtr ret;
2345
2346 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2347 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002348 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002349 return(NULL);
2350 }
2351 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2352 ret->type = XPATH_NODESET;
2353 ret->nodesetval = val;
2354 return(ret);
2355}
2356
2357/**
2358 * xmlXPathFreeNodeSetList:
2359 * @obj: an existing NodeSetList object
2360 *
2361 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2362 * the list contrary to xmlXPathFreeObject().
2363 */
2364void
2365xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2366 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002367 xmlFree(obj);
2368}
2369
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002370/**
2371 * xmlXPathDifference:
2372 * @nodes1: a node-set
2373 * @nodes2: a node-set
2374 *
2375 * Implements the EXSLT - Sets difference() function:
2376 * node-set set:difference (node-set, node-set)
2377 *
2378 * Returns the difference between the two node sets, or nodes1 if
2379 * nodes2 is empty
2380 */
2381xmlNodeSetPtr
2382xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2383 xmlNodeSetPtr ret;
2384 int i, l1;
2385 xmlNodePtr cur;
2386
2387 if (xmlXPathNodeSetIsEmpty(nodes2))
2388 return(nodes1);
2389
2390 ret = xmlXPathNodeSetCreate(NULL);
2391 if (xmlXPathNodeSetIsEmpty(nodes1))
2392 return(ret);
2393
2394 l1 = xmlXPathNodeSetGetLength(nodes1);
2395
2396 for (i = 0; i < l1; i++) {
2397 cur = xmlXPathNodeSetItem(nodes1, i);
2398 if (!xmlXPathNodeSetContains(nodes2, cur))
2399 xmlXPathNodeSetAddUnique(ret, cur);
2400 }
2401 return(ret);
2402}
2403
2404/**
2405 * xmlXPathIntersection:
2406 * @nodes1: a node-set
2407 * @nodes2: a node-set
2408 *
2409 * Implements the EXSLT - Sets intersection() function:
2410 * node-set set:intersection (node-set, node-set)
2411 *
2412 * Returns a node set comprising the nodes that are within both the
2413 * node sets passed as arguments
2414 */
2415xmlNodeSetPtr
2416xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2417 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2418 int i, l1;
2419 xmlNodePtr cur;
2420
2421 if (xmlXPathNodeSetIsEmpty(nodes1))
2422 return(ret);
2423 if (xmlXPathNodeSetIsEmpty(nodes2))
2424 return(ret);
2425
2426 l1 = xmlXPathNodeSetGetLength(nodes1);
2427
2428 for (i = 0; i < l1; i++) {
2429 cur = xmlXPathNodeSetItem(nodes1, i);
2430 if (xmlXPathNodeSetContains(nodes2, cur))
2431 xmlXPathNodeSetAddUnique(ret, cur);
2432 }
2433 return(ret);
2434}
2435
2436/**
2437 * xmlXPathDistinctSorted:
2438 * @nodes: a node-set, sorted by document order
2439 *
2440 * Implements the EXSLT - Sets distinct() function:
2441 * node-set set:distinct (node-set)
2442 *
2443 * Returns a subset of the nodes contained in @nodes, or @nodes if
2444 * it is empty
2445 */
2446xmlNodeSetPtr
2447xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2448 xmlNodeSetPtr ret;
2449 xmlHashTablePtr hash;
2450 int i, l;
2451 xmlChar * strval;
2452 xmlNodePtr cur;
2453
2454 if (xmlXPathNodeSetIsEmpty(nodes))
2455 return(nodes);
2456
2457 ret = xmlXPathNodeSetCreate(NULL);
2458 l = xmlXPathNodeSetGetLength(nodes);
2459 hash = xmlHashCreate (l);
2460 for (i = 0; i < l; i++) {
2461 cur = xmlXPathNodeSetItem(nodes, i);
2462 strval = xmlXPathCastNodeToString(cur);
2463 if (xmlHashLookup(hash, strval) == NULL) {
2464 xmlHashAddEntry(hash, strval, strval);
2465 xmlXPathNodeSetAddUnique(ret, cur);
2466 } else {
2467 xmlFree(strval);
2468 }
2469 }
2470 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2471 return(ret);
2472}
2473
2474/**
2475 * xmlXPathDistinct:
2476 * @nodes: a node-set
2477 *
2478 * Implements the EXSLT - Sets distinct() function:
2479 * node-set set:distinct (node-set)
2480 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2481 * is called with the sorted node-set
2482 *
2483 * Returns a subset of the nodes contained in @nodes, or @nodes if
2484 * it is empty
2485 */
2486xmlNodeSetPtr
2487xmlXPathDistinct (xmlNodeSetPtr nodes) {
2488 if (xmlXPathNodeSetIsEmpty(nodes))
2489 return(nodes);
2490
2491 xmlXPathNodeSetSort(nodes);
2492 return(xmlXPathDistinctSorted(nodes));
2493}
2494
2495/**
2496 * xmlXPathHasSameNodes:
2497 * @nodes1: a node-set
2498 * @nodes2: a node-set
2499 *
2500 * Implements the EXSLT - Sets has-same-nodes function:
2501 * boolean set:has-same-node(node-set, node-set)
2502 *
2503 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2504 * otherwise
2505 */
2506int
2507xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2508 int i, l;
2509 xmlNodePtr cur;
2510
2511 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2512 xmlXPathNodeSetIsEmpty(nodes2))
2513 return(0);
2514
2515 l = xmlXPathNodeSetGetLength(nodes1);
2516 for (i = 0; i < l; i++) {
2517 cur = xmlXPathNodeSetItem(nodes1, i);
2518 if (xmlXPathNodeSetContains(nodes2, cur))
2519 return(1);
2520 }
2521 return(0);
2522}
2523
2524/**
2525 * xmlXPathNodeLeadingSorted:
2526 * @nodes: a node-set, sorted by document order
2527 * @node: a node
2528 *
2529 * Implements the EXSLT - Sets leading() function:
2530 * node-set set:leading (node-set, node-set)
2531 *
2532 * Returns the nodes in @nodes that precede @node in document order,
2533 * @nodes if @node is NULL or an empty node-set if @nodes
2534 * doesn't contain @node
2535 */
2536xmlNodeSetPtr
2537xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2538 int i, l;
2539 xmlNodePtr cur;
2540 xmlNodeSetPtr ret;
2541
2542 if (node == NULL)
2543 return(nodes);
2544
2545 ret = xmlXPathNodeSetCreate(NULL);
2546 if (xmlXPathNodeSetIsEmpty(nodes) ||
2547 (!xmlXPathNodeSetContains(nodes, node)))
2548 return(ret);
2549
2550 l = xmlXPathNodeSetGetLength(nodes);
2551 for (i = 0; i < l; i++) {
2552 cur = xmlXPathNodeSetItem(nodes, i);
2553 if (cur == node)
2554 break;
2555 xmlXPathNodeSetAddUnique(ret, cur);
2556 }
2557 return(ret);
2558}
2559
2560/**
2561 * xmlXPathNodeLeading:
2562 * @nodes: a node-set
2563 * @node: a node
2564 *
2565 * Implements the EXSLT - Sets leading() function:
2566 * node-set set:leading (node-set, node-set)
2567 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2568 * is called.
2569 *
2570 * Returns the nodes in @nodes that precede @node in document order,
2571 * @nodes if @node is NULL or an empty node-set if @nodes
2572 * doesn't contain @node
2573 */
2574xmlNodeSetPtr
2575xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2576 xmlXPathNodeSetSort(nodes);
2577 return(xmlXPathNodeLeadingSorted(nodes, node));
2578}
2579
2580/**
2581 * xmlXPathLeadingSorted:
2582 * @nodes1: a node-set, sorted by document order
2583 * @nodes2: a node-set, sorted by document order
2584 *
2585 * Implements the EXSLT - Sets leading() function:
2586 * node-set set:leading (node-set, node-set)
2587 *
2588 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2589 * in document order, @nodes1 if @nodes2 is NULL or empty or
2590 * an empty node-set if @nodes1 doesn't contain @nodes2
2591 */
2592xmlNodeSetPtr
2593xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2594 if (xmlXPathNodeSetIsEmpty(nodes2))
2595 return(nodes1);
2596 return(xmlXPathNodeLeadingSorted(nodes1,
2597 xmlXPathNodeSetItem(nodes2, 1)));
2598}
2599
2600/**
2601 * xmlXPathLeading:
2602 * @nodes1: a node-set
2603 * @nodes2: a node-set
2604 *
2605 * Implements the EXSLT - Sets leading() function:
2606 * node-set set:leading (node-set, node-set)
2607 * @nodes1 and @nodes2 are sorted by document order, then
2608 * #exslSetsLeadingSorted is called.
2609 *
2610 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2611 * in document order, @nodes1 if @nodes2 is NULL or empty or
2612 * an empty node-set if @nodes1 doesn't contain @nodes2
2613 */
2614xmlNodeSetPtr
2615xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2616 if (xmlXPathNodeSetIsEmpty(nodes2))
2617 return(nodes1);
2618 if (xmlXPathNodeSetIsEmpty(nodes1))
2619 return(xmlXPathNodeSetCreate(NULL));
2620 xmlXPathNodeSetSort(nodes1);
2621 xmlXPathNodeSetSort(nodes2);
2622 return(xmlXPathNodeLeadingSorted(nodes1,
2623 xmlXPathNodeSetItem(nodes2, 1)));
2624}
2625
2626/**
2627 * xmlXPathNodeTrailingSorted:
2628 * @nodes: a node-set, sorted by document order
2629 * @node: a node
2630 *
2631 * Implements the EXSLT - Sets trailing() function:
2632 * node-set set:trailing (node-set, node-set)
2633 *
2634 * Returns the nodes in @nodes that follow @node in document order,
2635 * @nodes if @node is NULL or an empty node-set if @nodes
2636 * doesn't contain @node
2637 */
2638xmlNodeSetPtr
2639xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2640 int i, l;
2641 xmlNodePtr cur;
2642 xmlNodeSetPtr ret;
2643
2644 if (node == NULL)
2645 return(nodes);
2646
2647 ret = xmlXPathNodeSetCreate(NULL);
2648 if (xmlXPathNodeSetIsEmpty(nodes) ||
2649 (!xmlXPathNodeSetContains(nodes, node)))
2650 return(ret);
2651
2652 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002653 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002654 cur = xmlXPathNodeSetItem(nodes, i);
2655 if (cur == node)
2656 break;
2657 xmlXPathNodeSetAddUnique(ret, cur);
2658 }
2659 return(ret);
2660}
2661
2662/**
2663 * xmlXPathNodeTrailing:
2664 * @nodes: a node-set
2665 * @node: a node
2666 *
2667 * Implements the EXSLT - Sets trailing() function:
2668 * node-set set:trailing (node-set, node-set)
2669 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2670 * is called.
2671 *
2672 * Returns the nodes in @nodes that follow @node in document order,
2673 * @nodes if @node is NULL or an empty node-set if @nodes
2674 * doesn't contain @node
2675 */
2676xmlNodeSetPtr
2677xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2678 xmlXPathNodeSetSort(nodes);
2679 return(xmlXPathNodeTrailingSorted(nodes, node));
2680}
2681
2682/**
2683 * xmlXPathTrailingSorted:
2684 * @nodes1: a node-set, sorted by document order
2685 * @nodes2: a node-set, sorted by document order
2686 *
2687 * Implements the EXSLT - Sets trailing() function:
2688 * node-set set:trailing (node-set, node-set)
2689 *
2690 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2691 * in document order, @nodes1 if @nodes2 is NULL or empty or
2692 * an empty node-set if @nodes1 doesn't contain @nodes2
2693 */
2694xmlNodeSetPtr
2695xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2696 if (xmlXPathNodeSetIsEmpty(nodes2))
2697 return(nodes1);
2698 return(xmlXPathNodeTrailingSorted(nodes1,
2699 xmlXPathNodeSetItem(nodes2, 0)));
2700}
2701
2702/**
2703 * xmlXPathTrailing:
2704 * @nodes1: a node-set
2705 * @nodes2: a node-set
2706 *
2707 * Implements the EXSLT - Sets trailing() function:
2708 * node-set set:trailing (node-set, node-set)
2709 * @nodes1 and @nodes2 are sorted by document order, then
2710 * #xmlXPathTrailingSorted is called.
2711 *
2712 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2713 * in document order, @nodes1 if @nodes2 is NULL or empty or
2714 * an empty node-set if @nodes1 doesn't contain @nodes2
2715 */
2716xmlNodeSetPtr
2717xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2718 if (xmlXPathNodeSetIsEmpty(nodes2))
2719 return(nodes1);
2720 if (xmlXPathNodeSetIsEmpty(nodes1))
2721 return(xmlXPathNodeSetCreate(NULL));
2722 xmlXPathNodeSetSort(nodes1);
2723 xmlXPathNodeSetSort(nodes2);
2724 return(xmlXPathNodeTrailingSorted(nodes1,
2725 xmlXPathNodeSetItem(nodes2, 0)));
2726}
2727
Owen Taylor3473f882001-02-23 17:55:21 +00002728/************************************************************************
2729 * *
2730 * Routines to handle extra functions *
2731 * *
2732 ************************************************************************/
2733
2734/**
2735 * xmlXPathRegisterFunc:
2736 * @ctxt: the XPath context
2737 * @name: the function name
2738 * @f: the function implementation or NULL
2739 *
2740 * Register a new function. If @f is NULL it unregisters the function
2741 *
2742 * Returns 0 in case of success, -1 in case of error
2743 */
2744int
2745xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2746 xmlXPathFunction f) {
2747 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2748}
2749
2750/**
2751 * xmlXPathRegisterFuncNS:
2752 * @ctxt: the XPath context
2753 * @name: the function name
2754 * @ns_uri: the function namespace URI
2755 * @f: the function implementation or NULL
2756 *
2757 * Register a new function. If @f is NULL it unregisters the function
2758 *
2759 * Returns 0 in case of success, -1 in case of error
2760 */
2761int
2762xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2763 const xmlChar *ns_uri, xmlXPathFunction f) {
2764 if (ctxt == NULL)
2765 return(-1);
2766 if (name == NULL)
2767 return(-1);
2768
2769 if (ctxt->funcHash == NULL)
2770 ctxt->funcHash = xmlHashCreate(0);
2771 if (ctxt->funcHash == NULL)
2772 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002773 if (f == NULL)
2774 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
Owen Taylor3473f882001-02-23 17:55:21 +00002775 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2776}
2777
2778/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002779 * xmlXPathRegisterFuncLookup:
2780 * @ctxt: the XPath context
2781 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002782 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002783 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002784 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002785 */
2786void
2787xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2788 xmlXPathFuncLookupFunc f,
2789 void *funcCtxt) {
2790 if (ctxt == NULL)
2791 return;
2792 ctxt->funcLookupFunc = (void *) f;
2793 ctxt->funcLookupData = funcCtxt;
2794}
2795
2796/**
Owen Taylor3473f882001-02-23 17:55:21 +00002797 * xmlXPathFunctionLookup:
2798 * @ctxt: the XPath context
2799 * @name: the function name
2800 *
2801 * Search in the Function array of the context for the given
2802 * function.
2803 *
2804 * Returns the xmlXPathFunction or NULL if not found
2805 */
2806xmlXPathFunction
2807xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002808 if (ctxt == NULL)
2809 return (NULL);
2810
2811 if (ctxt->funcLookupFunc != NULL) {
2812 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002813 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002814
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002815 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002816 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002817 if (ret != NULL)
2818 return(ret);
2819 }
Owen Taylor3473f882001-02-23 17:55:21 +00002820 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2821}
2822
2823/**
2824 * xmlXPathFunctionLookupNS:
2825 * @ctxt: the XPath context
2826 * @name: the function name
2827 * @ns_uri: the function namespace URI
2828 *
2829 * Search in the Function array of the context for the given
2830 * function.
2831 *
2832 * Returns the xmlXPathFunction or NULL if not found
2833 */
2834xmlXPathFunction
2835xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2836 const xmlChar *ns_uri) {
2837 if (ctxt == NULL)
2838 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002839 if (name == NULL)
2840 return(NULL);
2841
Thomas Broyerba4ad322001-07-26 16:55:21 +00002842 if (ctxt->funcLookupFunc != NULL) {
2843 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002844 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002845
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002846 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002847 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002848 if (ret != NULL)
2849 return(ret);
2850 }
2851
2852 if (ctxt->funcHash == NULL)
2853 return(NULL);
2854
Owen Taylor3473f882001-02-23 17:55:21 +00002855 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2856}
2857
2858/**
2859 * xmlXPathRegisteredFuncsCleanup:
2860 * @ctxt: the XPath context
2861 *
2862 * Cleanup the XPath context data associated to registered functions
2863 */
2864void
2865xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2866 if (ctxt == NULL)
2867 return;
2868
2869 xmlHashFree(ctxt->funcHash, NULL);
2870 ctxt->funcHash = NULL;
2871}
2872
2873/************************************************************************
2874 * *
William M. Brack08171912003-12-29 02:52:11 +00002875 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00002876 * *
2877 ************************************************************************/
2878
2879/**
2880 * xmlXPathRegisterVariable:
2881 * @ctxt: the XPath context
2882 * @name: the variable name
2883 * @value: the variable value or NULL
2884 *
2885 * Register a new variable value. If @value is NULL it unregisters
2886 * the variable
2887 *
2888 * Returns 0 in case of success, -1 in case of error
2889 */
2890int
2891xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2892 xmlXPathObjectPtr value) {
2893 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2894}
2895
2896/**
2897 * xmlXPathRegisterVariableNS:
2898 * @ctxt: the XPath context
2899 * @name: the variable name
2900 * @ns_uri: the variable namespace URI
2901 * @value: the variable value or NULL
2902 *
2903 * Register a new variable value. If @value is NULL it unregisters
2904 * the variable
2905 *
2906 * Returns 0 in case of success, -1 in case of error
2907 */
2908int
2909xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2910 const xmlChar *ns_uri,
2911 xmlXPathObjectPtr value) {
2912 if (ctxt == NULL)
2913 return(-1);
2914 if (name == NULL)
2915 return(-1);
2916
2917 if (ctxt->varHash == NULL)
2918 ctxt->varHash = xmlHashCreate(0);
2919 if (ctxt->varHash == NULL)
2920 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002921 if (value == NULL)
2922 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2923 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002924 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2925 (void *) value,
2926 (xmlHashDeallocator)xmlXPathFreeObject));
2927}
2928
2929/**
2930 * xmlXPathRegisterVariableLookup:
2931 * @ctxt: the XPath context
2932 * @f: the lookup function
2933 * @data: the lookup data
2934 *
2935 * register an external mechanism to do variable lookup
2936 */
2937void
2938xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2939 xmlXPathVariableLookupFunc f, void *data) {
2940 if (ctxt == NULL)
2941 return;
2942 ctxt->varLookupFunc = (void *) f;
2943 ctxt->varLookupData = data;
2944}
2945
2946/**
2947 * xmlXPathVariableLookup:
2948 * @ctxt: the XPath context
2949 * @name: the variable name
2950 *
2951 * Search in the Variable array of the context for the given
2952 * variable value.
2953 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002954 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002955 */
2956xmlXPathObjectPtr
2957xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2958 if (ctxt == NULL)
2959 return(NULL);
2960
2961 if (ctxt->varLookupFunc != NULL) {
2962 xmlXPathObjectPtr ret;
2963
2964 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2965 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002966 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002967 }
2968 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2969}
2970
2971/**
2972 * xmlXPathVariableLookupNS:
2973 * @ctxt: the XPath context
2974 * @name: the variable name
2975 * @ns_uri: the variable namespace URI
2976 *
2977 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002978 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002979 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002980 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002981 */
2982xmlXPathObjectPtr
2983xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2984 const xmlChar *ns_uri) {
2985 if (ctxt == NULL)
2986 return(NULL);
2987
2988 if (ctxt->varLookupFunc != NULL) {
2989 xmlXPathObjectPtr ret;
2990
2991 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2992 (ctxt->varLookupData, name, ns_uri);
2993 if (ret != NULL) return(ret);
2994 }
2995
2996 if (ctxt->varHash == NULL)
2997 return(NULL);
2998 if (name == NULL)
2999 return(NULL);
3000
Daniel Veillard8c357d52001-07-03 23:43:33 +00003001 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3002 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00003003}
3004
3005/**
3006 * xmlXPathRegisteredVariablesCleanup:
3007 * @ctxt: the XPath context
3008 *
3009 * Cleanup the XPath context data associated to registered variables
3010 */
3011void
3012xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3013 if (ctxt == NULL)
3014 return;
3015
Daniel Veillard76d66f42001-05-16 21:05:17 +00003016 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00003017 ctxt->varHash = NULL;
3018}
3019
3020/**
3021 * xmlXPathRegisterNs:
3022 * @ctxt: the XPath context
3023 * @prefix: the namespace prefix
3024 * @ns_uri: the namespace name
3025 *
3026 * Register a new namespace. If @ns_uri is NULL it unregisters
3027 * the namespace
3028 *
3029 * Returns 0 in case of success, -1 in case of error
3030 */
3031int
3032xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3033 const xmlChar *ns_uri) {
3034 if (ctxt == NULL)
3035 return(-1);
3036 if (prefix == NULL)
3037 return(-1);
3038
3039 if (ctxt->nsHash == NULL)
3040 ctxt->nsHash = xmlHashCreate(10);
3041 if (ctxt->nsHash == NULL)
3042 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003043 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003044 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003045 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003046 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003047 (xmlHashDeallocator)xmlFree));
3048}
3049
3050/**
3051 * xmlXPathNsLookup:
3052 * @ctxt: the XPath context
3053 * @prefix: the namespace prefix value
3054 *
3055 * Search in the namespace declaration array of the context for the given
3056 * namespace name associated to the given prefix
3057 *
3058 * Returns the value or NULL if not found
3059 */
3060const xmlChar *
3061xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3062 if (ctxt == NULL)
3063 return(NULL);
3064 if (prefix == NULL)
3065 return(NULL);
3066
3067#ifdef XML_XML_NAMESPACE
3068 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3069 return(XML_XML_NAMESPACE);
3070#endif
3071
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003072 if (ctxt->namespaces != NULL) {
3073 int i;
3074
3075 for (i = 0;i < ctxt->nsNr;i++) {
3076 if ((ctxt->namespaces[i] != NULL) &&
3077 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3078 return(ctxt->namespaces[i]->href);
3079 }
3080 }
Owen Taylor3473f882001-02-23 17:55:21 +00003081
3082 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3083}
3084
3085/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003086 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003087 * @ctxt: the XPath context
3088 *
3089 * Cleanup the XPath context data associated to registered variables
3090 */
3091void
3092xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3093 if (ctxt == NULL)
3094 return;
3095
Daniel Veillard42766c02002-08-22 20:52:17 +00003096 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003097 ctxt->nsHash = NULL;
3098}
3099
3100/************************************************************************
3101 * *
3102 * Routines to handle Values *
3103 * *
3104 ************************************************************************/
3105
William M. Brack08171912003-12-29 02:52:11 +00003106/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003107
3108/**
3109 * xmlXPathNewFloat:
3110 * @val: the double value
3111 *
3112 * Create a new xmlXPathObjectPtr of type double and of value @val
3113 *
3114 * Returns the newly created object.
3115 */
3116xmlXPathObjectPtr
3117xmlXPathNewFloat(double val) {
3118 xmlXPathObjectPtr ret;
3119
3120 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3121 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003122 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003123 return(NULL);
3124 }
3125 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3126 ret->type = XPATH_NUMBER;
3127 ret->floatval = val;
3128 return(ret);
3129}
3130
3131/**
3132 * xmlXPathNewBoolean:
3133 * @val: the boolean value
3134 *
3135 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3136 *
3137 * Returns the newly created object.
3138 */
3139xmlXPathObjectPtr
3140xmlXPathNewBoolean(int val) {
3141 xmlXPathObjectPtr ret;
3142
3143 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3144 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003145 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003146 return(NULL);
3147 }
3148 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3149 ret->type = XPATH_BOOLEAN;
3150 ret->boolval = (val != 0);
3151 return(ret);
3152}
3153
3154/**
3155 * xmlXPathNewString:
3156 * @val: the xmlChar * value
3157 *
3158 * Create a new xmlXPathObjectPtr of type string and of value @val
3159 *
3160 * Returns the newly created object.
3161 */
3162xmlXPathObjectPtr
3163xmlXPathNewString(const xmlChar *val) {
3164 xmlXPathObjectPtr ret;
3165
3166 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3167 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003168 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003169 return(NULL);
3170 }
3171 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3172 ret->type = XPATH_STRING;
3173 if (val != NULL)
3174 ret->stringval = xmlStrdup(val);
3175 else
3176 ret->stringval = xmlStrdup((const xmlChar *)"");
3177 return(ret);
3178}
3179
3180/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003181 * xmlXPathWrapString:
3182 * @val: the xmlChar * value
3183 *
3184 * Wraps the @val string into an XPath object.
3185 *
3186 * Returns the newly created object.
3187 */
3188xmlXPathObjectPtr
3189xmlXPathWrapString (xmlChar *val) {
3190 xmlXPathObjectPtr ret;
3191
3192 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3193 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003194 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003195 return(NULL);
3196 }
3197 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3198 ret->type = XPATH_STRING;
3199 ret->stringval = val;
3200 return(ret);
3201}
3202
3203/**
Owen Taylor3473f882001-02-23 17:55:21 +00003204 * xmlXPathNewCString:
3205 * @val: the char * value
3206 *
3207 * Create a new xmlXPathObjectPtr of type string and of value @val
3208 *
3209 * Returns the newly created object.
3210 */
3211xmlXPathObjectPtr
3212xmlXPathNewCString(const char *val) {
3213 xmlXPathObjectPtr ret;
3214
3215 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3216 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003217 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003218 return(NULL);
3219 }
3220 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3221 ret->type = XPATH_STRING;
3222 ret->stringval = xmlStrdup(BAD_CAST val);
3223 return(ret);
3224}
3225
3226/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003227 * xmlXPathWrapCString:
3228 * @val: the char * value
3229 *
3230 * Wraps a string into an XPath object.
3231 *
3232 * Returns the newly created object.
3233 */
3234xmlXPathObjectPtr
3235xmlXPathWrapCString (char * val) {
3236 return(xmlXPathWrapString((xmlChar *)(val)));
3237}
3238
3239/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003240 * xmlXPathWrapExternal:
3241 * @val: the user data
3242 *
3243 * Wraps the @val data into an XPath object.
3244 *
3245 * Returns the newly created object.
3246 */
3247xmlXPathObjectPtr
3248xmlXPathWrapExternal (void *val) {
3249 xmlXPathObjectPtr ret;
3250
3251 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3252 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003253 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003254 return(NULL);
3255 }
3256 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3257 ret->type = XPATH_USERS;
3258 ret->user = val;
3259 return(ret);
3260}
3261
3262/**
Owen Taylor3473f882001-02-23 17:55:21 +00003263 * xmlXPathObjectCopy:
3264 * @val: the original object
3265 *
3266 * allocate a new copy of a given object
3267 *
3268 * Returns the newly created object.
3269 */
3270xmlXPathObjectPtr
3271xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3272 xmlXPathObjectPtr ret;
3273
3274 if (val == NULL)
3275 return(NULL);
3276
3277 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3278 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003279 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003280 return(NULL);
3281 }
3282 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3283 switch (val->type) {
3284 case XPATH_BOOLEAN:
3285 case XPATH_NUMBER:
3286 case XPATH_POINT:
3287 case XPATH_RANGE:
3288 break;
3289 case XPATH_STRING:
3290 ret->stringval = xmlStrdup(val->stringval);
3291 break;
3292 case XPATH_XSLT_TREE:
3293 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003294 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003295 xmlNodePtr cur, tmp;
3296 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003297
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003298 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003299 top = xmlNewDoc(NULL);
3300 top->name = (char *)
3301 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003302 ret->user = top;
3303 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003304 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003305 cur = val->nodesetval->nodeTab[0]->children;
3306 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003307 tmp = xmlDocCopyNode(cur, top, 1);
3308 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003309 cur = cur->next;
3310 }
3311 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003312 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003313 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003314 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003315 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003316 break;
3317 case XPATH_NODESET:
3318 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003319 /* Do not deallocate the copied tree value */
3320 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003321 break;
3322 case XPATH_LOCATIONSET:
3323#ifdef LIBXML_XPTR_ENABLED
3324 {
3325 xmlLocationSetPtr loc = val->user;
3326 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3327 break;
3328 }
3329#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003330 case XPATH_USERS:
3331 ret->user = val->user;
3332 break;
3333 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003334 xmlGenericError(xmlGenericErrorContext,
3335 "xmlXPathObjectCopy: unsupported type %d\n",
3336 val->type);
3337 break;
3338 }
3339 return(ret);
3340}
3341
3342/**
3343 * xmlXPathFreeObject:
3344 * @obj: the object to free
3345 *
3346 * Free up an xmlXPathObjectPtr object.
3347 */
3348void
3349xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3350 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003351 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003352 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003353 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003354 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003355 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003356 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003357 xmlXPathFreeValueTree(obj->nodesetval);
3358 } else {
3359 if (obj->nodesetval != NULL)
3360 xmlXPathFreeNodeSet(obj->nodesetval);
3361 }
Owen Taylor3473f882001-02-23 17:55:21 +00003362#ifdef LIBXML_XPTR_ENABLED
3363 } else if (obj->type == XPATH_LOCATIONSET) {
3364 if (obj->user != NULL)
3365 xmlXPtrFreeLocationSet(obj->user);
3366#endif
3367 } else if (obj->type == XPATH_STRING) {
3368 if (obj->stringval != NULL)
3369 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003370 }
3371
Owen Taylor3473f882001-02-23 17:55:21 +00003372 xmlFree(obj);
3373}
3374
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003375
3376/************************************************************************
3377 * *
3378 * Type Casting Routines *
3379 * *
3380 ************************************************************************/
3381
3382/**
3383 * xmlXPathCastBooleanToString:
3384 * @val: a boolean
3385 *
3386 * Converts a boolean to its string value.
3387 *
3388 * Returns a newly allocated string.
3389 */
3390xmlChar *
3391xmlXPathCastBooleanToString (int val) {
3392 xmlChar *ret;
3393 if (val)
3394 ret = xmlStrdup((const xmlChar *) "true");
3395 else
3396 ret = xmlStrdup((const xmlChar *) "false");
3397 return(ret);
3398}
3399
3400/**
3401 * xmlXPathCastNumberToString:
3402 * @val: a number
3403 *
3404 * Converts a number to its string value.
3405 *
3406 * Returns a newly allocated string.
3407 */
3408xmlChar *
3409xmlXPathCastNumberToString (double val) {
3410 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003411 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003412 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003413 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003414 break;
3415 case -1:
3416 ret = xmlStrdup((const xmlChar *) "-Infinity");
3417 break;
3418 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003419 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003420 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003421 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3422 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003423 } else {
3424 /* could be improved */
3425 char buf[100];
3426 xmlXPathFormatNumber(val, buf, 100);
3427 ret = xmlStrdup((const xmlChar *) buf);
3428 }
3429 }
3430 return(ret);
3431}
3432
3433/**
3434 * xmlXPathCastNodeToString:
3435 * @node: a node
3436 *
3437 * Converts a node to its string value.
3438 *
3439 * Returns a newly allocated string.
3440 */
3441xmlChar *
3442xmlXPathCastNodeToString (xmlNodePtr node) {
3443 return(xmlNodeGetContent(node));
3444}
3445
3446/**
3447 * xmlXPathCastNodeSetToString:
3448 * @ns: a node-set
3449 *
3450 * Converts a node-set to its string value.
3451 *
3452 * Returns a newly allocated string.
3453 */
3454xmlChar *
3455xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3456 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3457 return(xmlStrdup((const xmlChar *) ""));
3458
3459 xmlXPathNodeSetSort(ns);
3460 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3461}
3462
3463/**
3464 * xmlXPathCastToString:
3465 * @val: an XPath object
3466 *
3467 * Converts an existing object to its string() equivalent
3468 *
3469 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003470 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003471 * string object).
3472 */
3473xmlChar *
3474xmlXPathCastToString(xmlXPathObjectPtr val) {
3475 xmlChar *ret = NULL;
3476
3477 if (val == NULL)
3478 return(xmlStrdup((const xmlChar *) ""));
3479 switch (val->type) {
3480 case XPATH_UNDEFINED:
3481#ifdef DEBUG_EXPR
3482 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3483#endif
3484 ret = xmlStrdup((const xmlChar *) "");
3485 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003486 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003487 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003488 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3489 break;
3490 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003491 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003492 case XPATH_BOOLEAN:
3493 ret = xmlXPathCastBooleanToString(val->boolval);
3494 break;
3495 case XPATH_NUMBER: {
3496 ret = xmlXPathCastNumberToString(val->floatval);
3497 break;
3498 }
3499 case XPATH_USERS:
3500 case XPATH_POINT:
3501 case XPATH_RANGE:
3502 case XPATH_LOCATIONSET:
3503 TODO
3504 ret = xmlStrdup((const xmlChar *) "");
3505 break;
3506 }
3507 return(ret);
3508}
3509
3510/**
3511 * xmlXPathConvertString:
3512 * @val: an XPath object
3513 *
3514 * Converts an existing object to its string() equivalent
3515 *
3516 * Returns the new object, the old one is freed (or the operation
3517 * is done directly on @val)
3518 */
3519xmlXPathObjectPtr
3520xmlXPathConvertString(xmlXPathObjectPtr val) {
3521 xmlChar *res = NULL;
3522
3523 if (val == NULL)
3524 return(xmlXPathNewCString(""));
3525
3526 switch (val->type) {
3527 case XPATH_UNDEFINED:
3528#ifdef DEBUG_EXPR
3529 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3530#endif
3531 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003532 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003533 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003534 res = xmlXPathCastNodeSetToString(val->nodesetval);
3535 break;
3536 case XPATH_STRING:
3537 return(val);
3538 case XPATH_BOOLEAN:
3539 res = xmlXPathCastBooleanToString(val->boolval);
3540 break;
3541 case XPATH_NUMBER:
3542 res = xmlXPathCastNumberToString(val->floatval);
3543 break;
3544 case XPATH_USERS:
3545 case XPATH_POINT:
3546 case XPATH_RANGE:
3547 case XPATH_LOCATIONSET:
3548 TODO;
3549 break;
3550 }
3551 xmlXPathFreeObject(val);
3552 if (res == NULL)
3553 return(xmlXPathNewCString(""));
3554 return(xmlXPathWrapString(res));
3555}
3556
3557/**
3558 * xmlXPathCastBooleanToNumber:
3559 * @val: a boolean
3560 *
3561 * Converts a boolean to its number value
3562 *
3563 * Returns the number value
3564 */
3565double
3566xmlXPathCastBooleanToNumber(int val) {
3567 if (val)
3568 return(1.0);
3569 return(0.0);
3570}
3571
3572/**
3573 * xmlXPathCastStringToNumber:
3574 * @val: a string
3575 *
3576 * Converts a string to its number value
3577 *
3578 * Returns the number value
3579 */
3580double
3581xmlXPathCastStringToNumber(const xmlChar * val) {
3582 return(xmlXPathStringEvalNumber(val));
3583}
3584
3585/**
3586 * xmlXPathCastNodeToNumber:
3587 * @node: a node
3588 *
3589 * Converts a node to its number value
3590 *
3591 * Returns the number value
3592 */
3593double
3594xmlXPathCastNodeToNumber (xmlNodePtr node) {
3595 xmlChar *strval;
3596 double ret;
3597
3598 if (node == NULL)
3599 return(xmlXPathNAN);
3600 strval = xmlXPathCastNodeToString(node);
3601 if (strval == NULL)
3602 return(xmlXPathNAN);
3603 ret = xmlXPathCastStringToNumber(strval);
3604 xmlFree(strval);
3605
3606 return(ret);
3607}
3608
3609/**
3610 * xmlXPathCastNodeSetToNumber:
3611 * @ns: a node-set
3612 *
3613 * Converts a node-set to its number value
3614 *
3615 * Returns the number value
3616 */
3617double
3618xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3619 xmlChar *str;
3620 double ret;
3621
3622 if (ns == NULL)
3623 return(xmlXPathNAN);
3624 str = xmlXPathCastNodeSetToString(ns);
3625 ret = xmlXPathCastStringToNumber(str);
3626 xmlFree(str);
3627 return(ret);
3628}
3629
3630/**
3631 * xmlXPathCastToNumber:
3632 * @val: an XPath object
3633 *
3634 * Converts an XPath object to its number value
3635 *
3636 * Returns the number value
3637 */
3638double
3639xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3640 double ret = 0.0;
3641
3642 if (val == NULL)
3643 return(xmlXPathNAN);
3644 switch (val->type) {
3645 case XPATH_UNDEFINED:
3646#ifdef DEGUB_EXPR
3647 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3648#endif
3649 ret = xmlXPathNAN;
3650 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003651 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003652 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003653 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3654 break;
3655 case XPATH_STRING:
3656 ret = xmlXPathCastStringToNumber(val->stringval);
3657 break;
3658 case XPATH_NUMBER:
3659 ret = val->floatval;
3660 break;
3661 case XPATH_BOOLEAN:
3662 ret = xmlXPathCastBooleanToNumber(val->boolval);
3663 break;
3664 case XPATH_USERS:
3665 case XPATH_POINT:
3666 case XPATH_RANGE:
3667 case XPATH_LOCATIONSET:
3668 TODO;
3669 ret = xmlXPathNAN;
3670 break;
3671 }
3672 return(ret);
3673}
3674
3675/**
3676 * xmlXPathConvertNumber:
3677 * @val: an XPath object
3678 *
3679 * Converts an existing object to its number() equivalent
3680 *
3681 * Returns the new object, the old one is freed (or the operation
3682 * is done directly on @val)
3683 */
3684xmlXPathObjectPtr
3685xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3686 xmlXPathObjectPtr ret;
3687
3688 if (val == NULL)
3689 return(xmlXPathNewFloat(0.0));
3690 if (val->type == XPATH_NUMBER)
3691 return(val);
3692 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3693 xmlXPathFreeObject(val);
3694 return(ret);
3695}
3696
3697/**
3698 * xmlXPathCastNumberToBoolean:
3699 * @val: a number
3700 *
3701 * Converts a number to its boolean value
3702 *
3703 * Returns the boolean value
3704 */
3705int
3706xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003707 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003708 return(0);
3709 return(1);
3710}
3711
3712/**
3713 * xmlXPathCastStringToBoolean:
3714 * @val: a string
3715 *
3716 * Converts a string to its boolean value
3717 *
3718 * Returns the boolean value
3719 */
3720int
3721xmlXPathCastStringToBoolean (const xmlChar *val) {
3722 if ((val == NULL) || (xmlStrlen(val) == 0))
3723 return(0);
3724 return(1);
3725}
3726
3727/**
3728 * xmlXPathCastNodeSetToBoolean:
3729 * @ns: a node-set
3730 *
3731 * Converts a node-set to its boolean value
3732 *
3733 * Returns the boolean value
3734 */
3735int
3736xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3737 if ((ns == NULL) || (ns->nodeNr == 0))
3738 return(0);
3739 return(1);
3740}
3741
3742/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003743 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003744 * @val: an XPath object
3745 *
3746 * Converts an XPath object to its boolean value
3747 *
3748 * Returns the boolean value
3749 */
3750int
3751xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3752 int ret = 0;
3753
3754 if (val == NULL)
3755 return(0);
3756 switch (val->type) {
3757 case XPATH_UNDEFINED:
3758#ifdef DEBUG_EXPR
3759 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3760#endif
3761 ret = 0;
3762 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003763 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003764 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003765 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3766 break;
3767 case XPATH_STRING:
3768 ret = xmlXPathCastStringToBoolean(val->stringval);
3769 break;
3770 case XPATH_NUMBER:
3771 ret = xmlXPathCastNumberToBoolean(val->floatval);
3772 break;
3773 case XPATH_BOOLEAN:
3774 ret = val->boolval;
3775 break;
3776 case XPATH_USERS:
3777 case XPATH_POINT:
3778 case XPATH_RANGE:
3779 case XPATH_LOCATIONSET:
3780 TODO;
3781 ret = 0;
3782 break;
3783 }
3784 return(ret);
3785}
3786
3787
3788/**
3789 * xmlXPathConvertBoolean:
3790 * @val: an XPath object
3791 *
3792 * Converts an existing object to its boolean() equivalent
3793 *
3794 * Returns the new object, the old one is freed (or the operation
3795 * is done directly on @val)
3796 */
3797xmlXPathObjectPtr
3798xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3799 xmlXPathObjectPtr ret;
3800
3801 if (val == NULL)
3802 return(xmlXPathNewBoolean(0));
3803 if (val->type == XPATH_BOOLEAN)
3804 return(val);
3805 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3806 xmlXPathFreeObject(val);
3807 return(ret);
3808}
3809
Owen Taylor3473f882001-02-23 17:55:21 +00003810/************************************************************************
3811 * *
3812 * Routines to handle XPath contexts *
3813 * *
3814 ************************************************************************/
3815
3816/**
3817 * xmlXPathNewContext:
3818 * @doc: the XML document
3819 *
3820 * Create a new xmlXPathContext
3821 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003822 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003823 */
3824xmlXPathContextPtr
3825xmlXPathNewContext(xmlDocPtr doc) {
3826 xmlXPathContextPtr ret;
3827
3828 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3829 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003830 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003831 return(NULL);
3832 }
3833 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3834 ret->doc = doc;
3835 ret->node = NULL;
3836
3837 ret->varHash = NULL;
3838
3839 ret->nb_types = 0;
3840 ret->max_types = 0;
3841 ret->types = NULL;
3842
3843 ret->funcHash = xmlHashCreate(0);
3844
3845 ret->nb_axis = 0;
3846 ret->max_axis = 0;
3847 ret->axis = NULL;
3848
3849 ret->nsHash = NULL;
3850 ret->user = NULL;
3851
3852 ret->contextSize = -1;
3853 ret->proximityPosition = -1;
3854
3855 xmlXPathRegisterAllFunctions(ret);
3856
3857 return(ret);
3858}
3859
3860/**
3861 * xmlXPathFreeContext:
3862 * @ctxt: the context to free
3863 *
3864 * Free up an xmlXPathContext
3865 */
3866void
3867xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3868 xmlXPathRegisteredNsCleanup(ctxt);
3869 xmlXPathRegisteredFuncsCleanup(ctxt);
3870 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003871 xmlFree(ctxt);
3872}
3873
3874/************************************************************************
3875 * *
3876 * Routines to handle XPath parser contexts *
3877 * *
3878 ************************************************************************/
3879
3880#define CHECK_CTXT(ctxt) \
3881 if (ctxt == NULL) { \
3882 xmlGenericError(xmlGenericErrorContext, \
3883 "%s:%d Internal error: ctxt == NULL\n", \
3884 __FILE__, __LINE__); \
3885 } \
3886
3887
3888#define CHECK_CONTEXT(ctxt) \
3889 if (ctxt == NULL) { \
3890 xmlGenericError(xmlGenericErrorContext, \
3891 "%s:%d Internal error: no context\n", \
3892 __FILE__, __LINE__); \
3893 } \
3894 else if (ctxt->doc == NULL) { \
3895 xmlGenericError(xmlGenericErrorContext, \
3896 "%s:%d Internal error: no document\n", \
3897 __FILE__, __LINE__); \
3898 } \
3899 else if (ctxt->doc->children == NULL) { \
3900 xmlGenericError(xmlGenericErrorContext, \
3901 "%s:%d Internal error: document without root\n", \
3902 __FILE__, __LINE__); \
3903 } \
3904
3905
3906/**
3907 * xmlXPathNewParserContext:
3908 * @str: the XPath expression
3909 * @ctxt: the XPath context
3910 *
3911 * Create a new xmlXPathParserContext
3912 *
3913 * Returns the xmlXPathParserContext just allocated.
3914 */
3915xmlXPathParserContextPtr
3916xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3917 xmlXPathParserContextPtr ret;
3918
3919 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3920 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003921 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003922 return(NULL);
3923 }
3924 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3925 ret->cur = ret->base = str;
3926 ret->context = ctxt;
3927
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003928 ret->comp = xmlXPathNewCompExpr();
3929 if (ret->comp == NULL) {
3930 xmlFree(ret->valueTab);
3931 xmlFree(ret);
3932 return(NULL);
3933 }
Daniel Veillard4773df22004-01-23 13:15:13 +00003934 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
3935 ret->comp->dict = ctxt->dict;
3936 xmlDictReference(ret->comp->dict);
3937 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003938
3939 return(ret);
3940}
3941
3942/**
3943 * xmlXPathCompParserContext:
3944 * @comp: the XPath compiled expression
3945 * @ctxt: the XPath context
3946 *
3947 * Create a new xmlXPathParserContext when processing a compiled expression
3948 *
3949 * Returns the xmlXPathParserContext just allocated.
3950 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003951static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003952xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3953 xmlXPathParserContextPtr ret;
3954
3955 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3956 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003957 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003958 return(NULL);
3959 }
3960 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3961
Owen Taylor3473f882001-02-23 17:55:21 +00003962 /* Allocate the value stack */
3963 ret->valueTab = (xmlXPathObjectPtr *)
3964 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003965 if (ret->valueTab == NULL) {
3966 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003967 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003968 return(NULL);
3969 }
Owen Taylor3473f882001-02-23 17:55:21 +00003970 ret->valueNr = 0;
3971 ret->valueMax = 10;
3972 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003973
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003974 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003975 ret->comp = comp;
3976
Owen Taylor3473f882001-02-23 17:55:21 +00003977 return(ret);
3978}
3979
3980/**
3981 * xmlXPathFreeParserContext:
3982 * @ctxt: the context to free
3983 *
3984 * Free up an xmlXPathParserContext
3985 */
3986void
3987xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3988 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003989 xmlFree(ctxt->valueTab);
3990 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003991 if (ctxt->comp)
3992 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003993 xmlFree(ctxt);
3994}
3995
3996/************************************************************************
3997 * *
3998 * The implicit core function library *
3999 * *
4000 ************************************************************************/
4001
Owen Taylor3473f882001-02-23 17:55:21 +00004002/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004003 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00004004 * @node: a node pointer
4005 *
4006 * Function computing the beginning of the string value of the node,
4007 * used to speed up comparisons
4008 *
4009 * Returns an int usable as a hash
4010 */
4011static unsigned int
4012xmlXPathNodeValHash(xmlNodePtr node) {
4013 int len = 2;
4014 const xmlChar * string = NULL;
4015 xmlNodePtr tmp = NULL;
4016 unsigned int ret = 0;
4017
4018 if (node == NULL)
4019 return(0);
4020
Daniel Veillard9adc0462003-03-24 18:39:54 +00004021 if (node->type == XML_DOCUMENT_NODE) {
4022 tmp = xmlDocGetRootElement((xmlDocPtr) node);
4023 if (tmp == NULL)
4024 node = node->children;
4025 else
4026 node = tmp;
4027
4028 if (node == NULL)
4029 return(0);
4030 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004031
4032 switch (node->type) {
4033 case XML_COMMENT_NODE:
4034 case XML_PI_NODE:
4035 case XML_CDATA_SECTION_NODE:
4036 case XML_TEXT_NODE:
4037 string = node->content;
4038 if (string == NULL)
4039 return(0);
4040 if (string[0] == 0)
4041 return(0);
4042 return(((unsigned int) string[0]) +
4043 (((unsigned int) string[1]) << 8));
4044 case XML_NAMESPACE_DECL:
4045 string = ((xmlNsPtr)node)->href;
4046 if (string == NULL)
4047 return(0);
4048 if (string[0] == 0)
4049 return(0);
4050 return(((unsigned int) string[0]) +
4051 (((unsigned int) string[1]) << 8));
4052 case XML_ATTRIBUTE_NODE:
4053 tmp = ((xmlAttrPtr) node)->children;
4054 break;
4055 case XML_ELEMENT_NODE:
4056 tmp = node->children;
4057 break;
4058 default:
4059 return(0);
4060 }
4061 while (tmp != NULL) {
4062 switch (tmp->type) {
4063 case XML_COMMENT_NODE:
4064 case XML_PI_NODE:
4065 case XML_CDATA_SECTION_NODE:
4066 case XML_TEXT_NODE:
4067 string = tmp->content;
4068 break;
4069 case XML_NAMESPACE_DECL:
4070 string = ((xmlNsPtr)tmp)->href;
4071 break;
4072 default:
4073 break;
4074 }
4075 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004076 if (len == 1) {
4077 return(ret + (((unsigned int) string[0]) << 8));
4078 }
4079 if (string[1] == 0) {
4080 len = 1;
4081 ret = (unsigned int) string[0];
4082 } else {
4083 return(((unsigned int) string[0]) +
4084 (((unsigned int) string[1]) << 8));
4085 }
4086 }
4087 /*
4088 * Skip to next node
4089 */
4090 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4091 if (tmp->children->type != XML_ENTITY_DECL) {
4092 tmp = tmp->children;
4093 continue;
4094 }
4095 }
4096 if (tmp == node)
4097 break;
4098
4099 if (tmp->next != NULL) {
4100 tmp = tmp->next;
4101 continue;
4102 }
4103
4104 do {
4105 tmp = tmp->parent;
4106 if (tmp == NULL)
4107 break;
4108 if (tmp == node) {
4109 tmp = NULL;
4110 break;
4111 }
4112 if (tmp->next != NULL) {
4113 tmp = tmp->next;
4114 break;
4115 }
4116 } while (tmp != NULL);
4117 }
4118 return(ret);
4119}
4120
4121/**
4122 * xmlXPathStringHash:
4123 * @string: a string
4124 *
4125 * Function computing the beginning of the string value of the node,
4126 * used to speed up comparisons
4127 *
4128 * Returns an int usable as a hash
4129 */
4130static unsigned int
4131xmlXPathStringHash(const xmlChar * string) {
4132 if (string == NULL)
4133 return((unsigned int) 0);
4134 if (string[0] == 0)
4135 return(0);
4136 return(((unsigned int) string[0]) +
4137 (((unsigned int) string[1]) << 8));
4138}
4139
4140/**
Owen Taylor3473f882001-02-23 17:55:21 +00004141 * xmlXPathCompareNodeSetFloat:
4142 * @ctxt: the XPath Parser context
4143 * @inf: less than (1) or greater than (0)
4144 * @strict: is the comparison strict
4145 * @arg: the node set
4146 * @f: the value
4147 *
4148 * Implement the compare operation between a nodeset and a number
4149 * @ns < @val (1, 1, ...
4150 * @ns <= @val (1, 0, ...
4151 * @ns > @val (0, 1, ...
4152 * @ns >= @val (0, 0, ...
4153 *
4154 * If one object to be compared is a node-set and the other is a number,
4155 * then the comparison will be true if and only if there is a node in the
4156 * node-set such that the result of performing the comparison on the number
4157 * to be compared and on the result of converting the string-value of that
4158 * node to a number using the number function is true.
4159 *
4160 * Returns 0 or 1 depending on the results of the test.
4161 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004162static int
Owen Taylor3473f882001-02-23 17:55:21 +00004163xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4164 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4165 int i, ret = 0;
4166 xmlNodeSetPtr ns;
4167 xmlChar *str2;
4168
4169 if ((f == NULL) || (arg == NULL) ||
4170 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4171 xmlXPathFreeObject(arg);
4172 xmlXPathFreeObject(f);
4173 return(0);
4174 }
4175 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004176 if (ns != NULL) {
4177 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004178 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004179 if (str2 != NULL) {
4180 valuePush(ctxt,
4181 xmlXPathNewString(str2));
4182 xmlFree(str2);
4183 xmlXPathNumberFunction(ctxt, 1);
4184 valuePush(ctxt, xmlXPathObjectCopy(f));
4185 ret = xmlXPathCompareValues(ctxt, inf, strict);
4186 if (ret)
4187 break;
4188 }
4189 }
Owen Taylor3473f882001-02-23 17:55:21 +00004190 }
4191 xmlXPathFreeObject(arg);
4192 xmlXPathFreeObject(f);
4193 return(ret);
4194}
4195
4196/**
4197 * xmlXPathCompareNodeSetString:
4198 * @ctxt: the XPath Parser context
4199 * @inf: less than (1) or greater than (0)
4200 * @strict: is the comparison strict
4201 * @arg: the node set
4202 * @s: the value
4203 *
4204 * Implement the compare operation between a nodeset and a string
4205 * @ns < @val (1, 1, ...
4206 * @ns <= @val (1, 0, ...
4207 * @ns > @val (0, 1, ...
4208 * @ns >= @val (0, 0, ...
4209 *
4210 * If one object to be compared is a node-set and the other is a string,
4211 * then the comparison will be true if and only if there is a node in
4212 * the node-set such that the result of performing the comparison on the
4213 * string-value of the node and the other string is true.
4214 *
4215 * Returns 0 or 1 depending on the results of the test.
4216 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004217static int
Owen Taylor3473f882001-02-23 17:55:21 +00004218xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4219 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4220 int i, ret = 0;
4221 xmlNodeSetPtr ns;
4222 xmlChar *str2;
4223
4224 if ((s == NULL) || (arg == NULL) ||
4225 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4226 xmlXPathFreeObject(arg);
4227 xmlXPathFreeObject(s);
4228 return(0);
4229 }
4230 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004231 if (ns != NULL) {
4232 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004233 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004234 if (str2 != NULL) {
4235 valuePush(ctxt,
4236 xmlXPathNewString(str2));
4237 xmlFree(str2);
4238 valuePush(ctxt, xmlXPathObjectCopy(s));
4239 ret = xmlXPathCompareValues(ctxt, inf, strict);
4240 if (ret)
4241 break;
4242 }
4243 }
Owen Taylor3473f882001-02-23 17:55:21 +00004244 }
4245 xmlXPathFreeObject(arg);
4246 xmlXPathFreeObject(s);
4247 return(ret);
4248}
4249
4250/**
4251 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004252 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004253 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004254 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004255 * @arg2: the second node set object
4256 *
4257 * Implement the compare operation on nodesets:
4258 *
4259 * If both objects to be compared are node-sets, then the comparison
4260 * will be true if and only if there is a node in the first node-set
4261 * and a node in the second node-set such that the result of performing
4262 * the comparison on the string-values of the two nodes is true.
4263 * ....
4264 * When neither object to be compared is a node-set and the operator
4265 * is <=, <, >= or >, then the objects are compared by converting both
4266 * objects to numbers and comparing the numbers according to IEEE 754.
4267 * ....
4268 * The number function converts its argument to a number as follows:
4269 * - a string that consists of optional whitespace followed by an
4270 * optional minus sign followed by a Number followed by whitespace
4271 * is converted to the IEEE 754 number that is nearest (according
4272 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4273 * represented by the string; any other string is converted to NaN
4274 *
4275 * Conclusion all nodes need to be converted first to their string value
4276 * and then the comparison must be done when possible
4277 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004278static int
4279xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004280 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4281 int i, j, init = 0;
4282 double val1;
4283 double *values2;
4284 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004285 xmlNodeSetPtr ns1;
4286 xmlNodeSetPtr ns2;
4287
4288 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004289 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4290 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004291 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004292 }
Owen Taylor3473f882001-02-23 17:55:21 +00004293 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004294 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4295 xmlXPathFreeObject(arg1);
4296 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004297 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004298 }
Owen Taylor3473f882001-02-23 17:55:21 +00004299
4300 ns1 = arg1->nodesetval;
4301 ns2 = arg2->nodesetval;
4302
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004303 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004304 xmlXPathFreeObject(arg1);
4305 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004306 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004307 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004308 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004309 xmlXPathFreeObject(arg1);
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
4314 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4315 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004316 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004317 xmlXPathFreeObject(arg1);
4318 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004319 return(0);
4320 }
4321 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004322 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004323 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004324 continue;
4325 for (j = 0;j < ns2->nodeNr;j++) {
4326 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004327 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004328 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004329 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004330 continue;
4331 if (inf && strict)
4332 ret = (val1 < values2[j]);
4333 else if (inf && !strict)
4334 ret = (val1 <= values2[j]);
4335 else if (!inf && strict)
4336 ret = (val1 > values2[j]);
4337 else if (!inf && !strict)
4338 ret = (val1 >= values2[j]);
4339 if (ret)
4340 break;
4341 }
4342 if (ret)
4343 break;
4344 init = 1;
4345 }
4346 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004347 xmlXPathFreeObject(arg1);
4348 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004349 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004350}
4351
4352/**
4353 * xmlXPathCompareNodeSetValue:
4354 * @ctxt: the XPath Parser context
4355 * @inf: less than (1) or greater than (0)
4356 * @strict: is the comparison strict
4357 * @arg: the node set
4358 * @val: the value
4359 *
4360 * Implement the compare operation between a nodeset and a value
4361 * @ns < @val (1, 1, ...
4362 * @ns <= @val (1, 0, ...
4363 * @ns > @val (0, 1, ...
4364 * @ns >= @val (0, 0, ...
4365 *
4366 * If one object to be compared is a node-set and the other is a boolean,
4367 * then the comparison will be true if and only if the result of performing
4368 * the comparison on the boolean and on the result of converting
4369 * the node-set to a boolean using the boolean function is true.
4370 *
4371 * Returns 0 or 1 depending on the results of the test.
4372 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004373static int
Owen Taylor3473f882001-02-23 17:55:21 +00004374xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4375 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4376 if ((val == NULL) || (arg == NULL) ||
4377 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4378 return(0);
4379
4380 switch(val->type) {
4381 case XPATH_NUMBER:
4382 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4383 case XPATH_NODESET:
4384 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004385 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004386 case XPATH_STRING:
4387 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4388 case XPATH_BOOLEAN:
4389 valuePush(ctxt, arg);
4390 xmlXPathBooleanFunction(ctxt, 1);
4391 valuePush(ctxt, val);
4392 return(xmlXPathCompareValues(ctxt, inf, strict));
4393 default:
4394 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004395 }
4396 return(0);
4397}
4398
4399/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004400 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004401 * @arg: the nodeset object argument
4402 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004403 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004404 *
4405 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4406 * If one object to be compared is a node-set and the other is a string,
4407 * then the comparison will be true if and only if there is a node in
4408 * the node-set such that the result of performing the comparison on the
4409 * string-value of the node and the other string is true.
4410 *
4411 * Returns 0 or 1 depending on the results of the test.
4412 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004413static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004414xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004415{
Owen Taylor3473f882001-02-23 17:55:21 +00004416 int i;
4417 xmlNodeSetPtr ns;
4418 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004419 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004420
4421 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004422 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4423 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004424 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004425 /*
4426 * A NULL nodeset compared with a string is always false
4427 * (since there is no node equal, and no node not equal)
4428 */
4429 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004430 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004431 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004432 for (i = 0; i < ns->nodeNr; i++) {
4433 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4434 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4435 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4436 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004437 if (neq)
4438 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004439 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004440 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4441 if (neq)
4442 continue;
4443 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004444 } else if (neq) {
4445 if (str2 != NULL)
4446 xmlFree(str2);
4447 return (1);
4448 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004449 if (str2 != NULL)
4450 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004451 } else if (neq)
4452 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004453 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004454 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004455}
4456
4457/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004458 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004459 * @arg: the nodeset object argument
4460 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004461 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004462 *
4463 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4464 * If one object to be compared is a node-set and the other is a number,
4465 * then the comparison will be true if and only if there is a node in
4466 * the node-set such that the result of performing the comparison on the
4467 * number to be compared and on the result of converting the string-value
4468 * of that node to a number using the number function is true.
4469 *
4470 * Returns 0 or 1 depending on the results of the test.
4471 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004472static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004473xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4474 xmlXPathObjectPtr arg, double f, int neq) {
4475 int i, ret=0;
4476 xmlNodeSetPtr ns;
4477 xmlChar *str2;
4478 xmlXPathObjectPtr val;
4479 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004480
4481 if ((arg == NULL) ||
4482 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4483 return(0);
4484
William M. Brack0c022ad2002-07-12 00:56:01 +00004485 ns = arg->nodesetval;
4486 if (ns != NULL) {
4487 for (i=0;i<ns->nodeNr;i++) {
4488 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4489 if (str2 != NULL) {
4490 valuePush(ctxt, xmlXPathNewString(str2));
4491 xmlFree(str2);
4492 xmlXPathNumberFunction(ctxt, 1);
4493 val = valuePop(ctxt);
4494 v = val->floatval;
4495 xmlXPathFreeObject(val);
4496 if (!xmlXPathIsNaN(v)) {
4497 if ((!neq) && (v==f)) {
4498 ret = 1;
4499 break;
4500 } else if ((neq) && (v!=f)) {
4501 ret = 1;
4502 break;
4503 }
4504 }
4505 }
4506 }
4507 }
4508
4509 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004510}
4511
4512
4513/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004514 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004515 * @arg1: first nodeset object argument
4516 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004517 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004518 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004519 * Implement the equal / not equal operation on XPath nodesets:
4520 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004521 * If both objects to be compared are node-sets, then the comparison
4522 * will be true if and only if there is a node in the first node-set and
4523 * a node in the second node-set such that the result of performing the
4524 * comparison on the string-values of the two nodes is true.
4525 *
4526 * (needless to say, this is a costly operation)
4527 *
4528 * Returns 0 or 1 depending on the results of the test.
4529 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004530static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004531xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004532 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004533 unsigned int *hashs1;
4534 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004535 xmlChar **values1;
4536 xmlChar **values2;
4537 int ret = 0;
4538 xmlNodeSetPtr ns1;
4539 xmlNodeSetPtr ns2;
4540
4541 if ((arg1 == NULL) ||
4542 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4543 return(0);
4544 if ((arg2 == NULL) ||
4545 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4546 return(0);
4547
4548 ns1 = arg1->nodesetval;
4549 ns2 = arg2->nodesetval;
4550
Daniel Veillard911f49a2001-04-07 15:39:35 +00004551 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004552 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004553 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004554 return(0);
4555
4556 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004557 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004558 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004559 if (neq == 0)
4560 for (i = 0;i < ns1->nodeNr;i++)
4561 for (j = 0;j < ns2->nodeNr;j++)
4562 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4563 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004564
4565 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004566 if (values1 == NULL) {
4567 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004568 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004569 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004570 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4571 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004572 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004573 xmlFree(values1);
4574 return(0);
4575 }
Owen Taylor3473f882001-02-23 17:55:21 +00004576 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4577 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4578 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004579 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004580 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004581 xmlFree(values1);
4582 return(0);
4583 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004584 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4585 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004586 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004587 xmlFree(hashs1);
4588 xmlFree(values1);
4589 xmlFree(values2);
4590 return(0);
4591 }
Owen Taylor3473f882001-02-23 17:55:21 +00004592 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4593 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004594 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004595 for (j = 0;j < ns2->nodeNr;j++) {
4596 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004597 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004598 if (hashs1[i] != hashs2[j]) {
4599 if (neq) {
4600 ret = 1;
4601 break;
4602 }
4603 }
4604 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004605 if (values1[i] == NULL)
4606 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4607 if (values2[j] == NULL)
4608 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004609 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004610 if (ret)
4611 break;
4612 }
Owen Taylor3473f882001-02-23 17:55:21 +00004613 }
4614 if (ret)
4615 break;
4616 }
4617 for (i = 0;i < ns1->nodeNr;i++)
4618 if (values1[i] != NULL)
4619 xmlFree(values1[i]);
4620 for (j = 0;j < ns2->nodeNr;j++)
4621 if (values2[j] != NULL)
4622 xmlFree(values2[j]);
4623 xmlFree(values1);
4624 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004625 xmlFree(hashs1);
4626 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004627 return(ret);
4628}
4629
William M. Brack0c022ad2002-07-12 00:56:01 +00004630static int
4631xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4632 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004633 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004634 /*
4635 *At this point we are assured neither arg1 nor arg2
4636 *is a nodeset, so we can just pick the appropriate routine.
4637 */
Owen Taylor3473f882001-02-23 17:55:21 +00004638 switch (arg1->type) {
4639 case XPATH_UNDEFINED:
4640#ifdef DEBUG_EXPR
4641 xmlGenericError(xmlGenericErrorContext,
4642 "Equal: undefined\n");
4643#endif
4644 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004645 case XPATH_BOOLEAN:
4646 switch (arg2->type) {
4647 case XPATH_UNDEFINED:
4648#ifdef DEBUG_EXPR
4649 xmlGenericError(xmlGenericErrorContext,
4650 "Equal: undefined\n");
4651#endif
4652 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004653 case XPATH_BOOLEAN:
4654#ifdef DEBUG_EXPR
4655 xmlGenericError(xmlGenericErrorContext,
4656 "Equal: %d boolean %d \n",
4657 arg1->boolval, arg2->boolval);
4658#endif
4659 ret = (arg1->boolval == arg2->boolval);
4660 break;
4661 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004662 ret = (arg1->boolval ==
4663 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004664 break;
4665 case XPATH_STRING:
4666 if ((arg2->stringval == NULL) ||
4667 (arg2->stringval[0] == 0)) ret = 0;
4668 else
4669 ret = 1;
4670 ret = (arg1->boolval == ret);
4671 break;
4672 case XPATH_USERS:
4673 case XPATH_POINT:
4674 case XPATH_RANGE:
4675 case XPATH_LOCATIONSET:
4676 TODO
4677 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004678 case XPATH_NODESET:
4679 case XPATH_XSLT_TREE:
4680 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004681 }
4682 break;
4683 case XPATH_NUMBER:
4684 switch (arg2->type) {
4685 case XPATH_UNDEFINED:
4686#ifdef DEBUG_EXPR
4687 xmlGenericError(xmlGenericErrorContext,
4688 "Equal: undefined\n");
4689#endif
4690 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004691 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004692 ret = (arg2->boolval==
4693 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004694 break;
4695 case XPATH_STRING:
4696 valuePush(ctxt, arg2);
4697 xmlXPathNumberFunction(ctxt, 1);
4698 arg2 = valuePop(ctxt);
4699 /* no break on purpose */
4700 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004701 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004702 if (xmlXPathIsNaN(arg1->floatval) ||
4703 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004704 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004705 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4706 if (xmlXPathIsInf(arg2->floatval) == 1)
4707 ret = 1;
4708 else
4709 ret = 0;
4710 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4711 if (xmlXPathIsInf(arg2->floatval) == -1)
4712 ret = 1;
4713 else
4714 ret = 0;
4715 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4716 if (xmlXPathIsInf(arg1->floatval) == 1)
4717 ret = 1;
4718 else
4719 ret = 0;
4720 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4721 if (xmlXPathIsInf(arg1->floatval) == -1)
4722 ret = 1;
4723 else
4724 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004725 } else {
4726 ret = (arg1->floatval == arg2->floatval);
4727 }
Owen Taylor3473f882001-02-23 17:55:21 +00004728 break;
4729 case XPATH_USERS:
4730 case XPATH_POINT:
4731 case XPATH_RANGE:
4732 case XPATH_LOCATIONSET:
4733 TODO
4734 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004735 case XPATH_NODESET:
4736 case XPATH_XSLT_TREE:
4737 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004738 }
4739 break;
4740 case XPATH_STRING:
4741 switch (arg2->type) {
4742 case XPATH_UNDEFINED:
4743#ifdef DEBUG_EXPR
4744 xmlGenericError(xmlGenericErrorContext,
4745 "Equal: undefined\n");
4746#endif
4747 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004748 case XPATH_BOOLEAN:
4749 if ((arg1->stringval == NULL) ||
4750 (arg1->stringval[0] == 0)) ret = 0;
4751 else
4752 ret = 1;
4753 ret = (arg2->boolval == ret);
4754 break;
4755 case XPATH_STRING:
4756 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4757 break;
4758 case XPATH_NUMBER:
4759 valuePush(ctxt, arg1);
4760 xmlXPathNumberFunction(ctxt, 1);
4761 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004762 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004763 if (xmlXPathIsNaN(arg1->floatval) ||
4764 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004765 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004766 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4767 if (xmlXPathIsInf(arg2->floatval) == 1)
4768 ret = 1;
4769 else
4770 ret = 0;
4771 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4772 if (xmlXPathIsInf(arg2->floatval) == -1)
4773 ret = 1;
4774 else
4775 ret = 0;
4776 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4777 if (xmlXPathIsInf(arg1->floatval) == 1)
4778 ret = 1;
4779 else
4780 ret = 0;
4781 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4782 if (xmlXPathIsInf(arg1->floatval) == -1)
4783 ret = 1;
4784 else
4785 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004786 } else {
4787 ret = (arg1->floatval == arg2->floatval);
4788 }
Owen Taylor3473f882001-02-23 17:55:21 +00004789 break;
4790 case XPATH_USERS:
4791 case XPATH_POINT:
4792 case XPATH_RANGE:
4793 case XPATH_LOCATIONSET:
4794 TODO
4795 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004796 case XPATH_NODESET:
4797 case XPATH_XSLT_TREE:
4798 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004799 }
4800 break;
4801 case XPATH_USERS:
4802 case XPATH_POINT:
4803 case XPATH_RANGE:
4804 case XPATH_LOCATIONSET:
4805 TODO
4806 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004807 case XPATH_NODESET:
4808 case XPATH_XSLT_TREE:
4809 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004810 }
4811 xmlXPathFreeObject(arg1);
4812 xmlXPathFreeObject(arg2);
4813 return(ret);
4814}
4815
William M. Brack0c022ad2002-07-12 00:56:01 +00004816/**
4817 * xmlXPathEqualValues:
4818 * @ctxt: the XPath Parser context
4819 *
4820 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4821 *
4822 * Returns 0 or 1 depending on the results of the test.
4823 */
4824int
4825xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4826 xmlXPathObjectPtr arg1, arg2, argtmp;
4827 int ret = 0;
4828
4829 arg2 = valuePop(ctxt);
4830 arg1 = valuePop(ctxt);
4831 if ((arg1 == NULL) || (arg2 == NULL)) {
4832 if (arg1 != NULL)
4833 xmlXPathFreeObject(arg1);
4834 else
4835 xmlXPathFreeObject(arg2);
4836 XP_ERROR0(XPATH_INVALID_OPERAND);
4837 }
4838
4839 if (arg1 == arg2) {
4840#ifdef DEBUG_EXPR
4841 xmlGenericError(xmlGenericErrorContext,
4842 "Equal: by pointer\n");
4843#endif
4844 return(1);
4845 }
4846
4847 /*
4848 *If either argument is a nodeset, it's a 'special case'
4849 */
4850 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4851 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4852 /*
4853 *Hack it to assure arg1 is the nodeset
4854 */
4855 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4856 argtmp = arg2;
4857 arg2 = arg1;
4858 arg1 = argtmp;
4859 }
4860 switch (arg2->type) {
4861 case XPATH_UNDEFINED:
4862#ifdef DEBUG_EXPR
4863 xmlGenericError(xmlGenericErrorContext,
4864 "Equal: undefined\n");
4865#endif
4866 break;
4867 case XPATH_NODESET:
4868 case XPATH_XSLT_TREE:
4869 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4870 break;
4871 case XPATH_BOOLEAN:
4872 if ((arg1->nodesetval == NULL) ||
4873 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4874 else
4875 ret = 1;
4876 ret = (ret == arg2->boolval);
4877 break;
4878 case XPATH_NUMBER:
4879 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4880 break;
4881 case XPATH_STRING:
4882 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4883 break;
4884 case XPATH_USERS:
4885 case XPATH_POINT:
4886 case XPATH_RANGE:
4887 case XPATH_LOCATIONSET:
4888 TODO
4889 break;
4890 }
4891 xmlXPathFreeObject(arg1);
4892 xmlXPathFreeObject(arg2);
4893 return(ret);
4894 }
4895
4896 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4897}
4898
4899/**
4900 * xmlXPathNotEqualValues:
4901 * @ctxt: the XPath Parser context
4902 *
4903 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4904 *
4905 * Returns 0 or 1 depending on the results of the test.
4906 */
4907int
4908xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4909 xmlXPathObjectPtr arg1, arg2, argtmp;
4910 int ret = 0;
4911
4912 arg2 = valuePop(ctxt);
4913 arg1 = valuePop(ctxt);
4914 if ((arg1 == NULL) || (arg2 == NULL)) {
4915 if (arg1 != NULL)
4916 xmlXPathFreeObject(arg1);
4917 else
4918 xmlXPathFreeObject(arg2);
4919 XP_ERROR0(XPATH_INVALID_OPERAND);
4920 }
4921
4922 if (arg1 == arg2) {
4923#ifdef DEBUG_EXPR
4924 xmlGenericError(xmlGenericErrorContext,
4925 "NotEqual: by pointer\n");
4926#endif
4927 return(0);
4928 }
4929
4930 /*
4931 *If either argument is a nodeset, it's a 'special case'
4932 */
4933 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4934 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4935 /*
4936 *Hack it to assure arg1 is the nodeset
4937 */
4938 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4939 argtmp = arg2;
4940 arg2 = arg1;
4941 arg1 = argtmp;
4942 }
4943 switch (arg2->type) {
4944 case XPATH_UNDEFINED:
4945#ifdef DEBUG_EXPR
4946 xmlGenericError(xmlGenericErrorContext,
4947 "NotEqual: undefined\n");
4948#endif
4949 break;
4950 case XPATH_NODESET:
4951 case XPATH_XSLT_TREE:
4952 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4953 break;
4954 case XPATH_BOOLEAN:
4955 if ((arg1->nodesetval == NULL) ||
4956 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4957 else
4958 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004959 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004960 break;
4961 case XPATH_NUMBER:
4962 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4963 break;
4964 case XPATH_STRING:
4965 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4966 break;
4967 case XPATH_USERS:
4968 case XPATH_POINT:
4969 case XPATH_RANGE:
4970 case XPATH_LOCATIONSET:
4971 TODO
4972 break;
4973 }
4974 xmlXPathFreeObject(arg1);
4975 xmlXPathFreeObject(arg2);
4976 return(ret);
4977 }
4978
4979 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4980}
Owen Taylor3473f882001-02-23 17:55:21 +00004981
4982/**
4983 * xmlXPathCompareValues:
4984 * @ctxt: the XPath Parser context
4985 * @inf: less than (1) or greater than (0)
4986 * @strict: is the comparison strict
4987 *
4988 * Implement the compare operation on XPath objects:
4989 * @arg1 < @arg2 (1, 1, ...
4990 * @arg1 <= @arg2 (1, 0, ...
4991 * @arg1 > @arg2 (0, 1, ...
4992 * @arg1 >= @arg2 (0, 0, ...
4993 *
4994 * When neither object to be compared is a node-set and the operator is
4995 * <=, <, >=, >, then the objects are compared by converted both objects
4996 * to numbers and comparing the numbers according to IEEE 754. The <
4997 * comparison will be true if and only if the first number is less than the
4998 * second number. The <= comparison will be true if and only if the first
4999 * number is less than or equal to the second number. The > comparison
5000 * will be true if and only if the first number is greater than the second
5001 * number. The >= comparison will be true if and only if the first number
5002 * is greater than or equal to the second number.
5003 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005004 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005005 */
5006int
5007xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005008 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005009 xmlXPathObjectPtr arg1, arg2;
5010
William M. Brack0c022ad2002-07-12 00:56:01 +00005011 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005012 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005013 if ((arg1 == NULL) || (arg2 == NULL)) {
5014 if (arg1 != NULL)
5015 xmlXPathFreeObject(arg1);
5016 else
5017 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005018 XP_ERROR0(XPATH_INVALID_OPERAND);
5019 }
5020
William M. Brack0c022ad2002-07-12 00:56:01 +00005021 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5022 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5023 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5024 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005025 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005026 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005027 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005028 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5029 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005030 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005031 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5032 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005033 }
5034 }
5035 return(ret);
5036 }
5037
5038 if (arg1->type != XPATH_NUMBER) {
5039 valuePush(ctxt, arg1);
5040 xmlXPathNumberFunction(ctxt, 1);
5041 arg1 = valuePop(ctxt);
5042 }
5043 if (arg1->type != XPATH_NUMBER) {
5044 xmlXPathFreeObject(arg1);
5045 xmlXPathFreeObject(arg2);
5046 XP_ERROR0(XPATH_INVALID_OPERAND);
5047 }
5048 if (arg2->type != XPATH_NUMBER) {
5049 valuePush(ctxt, arg2);
5050 xmlXPathNumberFunction(ctxt, 1);
5051 arg2 = valuePop(ctxt);
5052 }
5053 if (arg2->type != XPATH_NUMBER) {
5054 xmlXPathFreeObject(arg1);
5055 xmlXPathFreeObject(arg2);
5056 XP_ERROR0(XPATH_INVALID_OPERAND);
5057 }
5058 /*
5059 * Add tests for infinity and nan
5060 * => feedback on 3.4 for Inf and NaN
5061 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005062 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005063 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005064 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005065 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005066 arg1i=xmlXPathIsInf(arg1->floatval);
5067 arg2i=xmlXPathIsInf(arg2->floatval);
5068 if (inf && strict) {
5069 if ((arg1i == -1 && arg2i != -1) ||
5070 (arg2i == 1 && arg1i != 1)) {
5071 ret = 1;
5072 } else if (arg1i == 0 && arg2i == 0) {
5073 ret = (arg1->floatval < arg2->floatval);
5074 } else {
5075 ret = 0;
5076 }
5077 }
5078 else if (inf && !strict) {
5079 if (arg1i == -1 || arg2i == 1) {
5080 ret = 1;
5081 } else if (arg1i == 0 && arg2i == 0) {
5082 ret = (arg1->floatval <= arg2->floatval);
5083 } else {
5084 ret = 0;
5085 }
5086 }
5087 else if (!inf && strict) {
5088 if ((arg1i == 1 && arg2i != 1) ||
5089 (arg2i == -1 && arg1i != -1)) {
5090 ret = 1;
5091 } else if (arg1i == 0 && arg2i == 0) {
5092 ret = (arg1->floatval > arg2->floatval);
5093 } else {
5094 ret = 0;
5095 }
5096 }
5097 else if (!inf && !strict) {
5098 if (arg1i == 1 || arg2i == -1) {
5099 ret = 1;
5100 } else if (arg1i == 0 && arg2i == 0) {
5101 ret = (arg1->floatval >= arg2->floatval);
5102 } else {
5103 ret = 0;
5104 }
5105 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005106 }
Owen Taylor3473f882001-02-23 17:55:21 +00005107 xmlXPathFreeObject(arg1);
5108 xmlXPathFreeObject(arg2);
5109 return(ret);
5110}
5111
5112/**
5113 * xmlXPathValueFlipSign:
5114 * @ctxt: the XPath Parser context
5115 *
5116 * Implement the unary - operation on an XPath object
5117 * The numeric operators convert their operands to numbers as if
5118 * by calling the number function.
5119 */
5120void
5121xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005122 CAST_TO_NUMBER;
5123 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005124 if (xmlXPathIsNaN(ctxt->value->floatval))
5125 ctxt->value->floatval=xmlXPathNAN;
5126 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5127 ctxt->value->floatval=xmlXPathNINF;
5128 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5129 ctxt->value->floatval=xmlXPathPINF;
5130 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005131 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5132 ctxt->value->floatval = xmlXPathNZERO;
5133 else
5134 ctxt->value->floatval = 0;
5135 }
5136 else
5137 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005138}
5139
5140/**
5141 * xmlXPathAddValues:
5142 * @ctxt: the XPath Parser context
5143 *
5144 * Implement the add operation on XPath objects:
5145 * The numeric operators convert their operands to numbers as if
5146 * by calling the number function.
5147 */
5148void
5149xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5150 xmlXPathObjectPtr arg;
5151 double val;
5152
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005153 arg = valuePop(ctxt);
5154 if (arg == NULL)
5155 XP_ERROR(XPATH_INVALID_OPERAND);
5156 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005157 xmlXPathFreeObject(arg);
5158
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005159 CAST_TO_NUMBER;
5160 CHECK_TYPE(XPATH_NUMBER);
5161 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005162}
5163
5164/**
5165 * xmlXPathSubValues:
5166 * @ctxt: the XPath Parser context
5167 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005168 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005169 * The numeric operators convert their operands to numbers as if
5170 * by calling the number function.
5171 */
5172void
5173xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5174 xmlXPathObjectPtr arg;
5175 double val;
5176
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005177 arg = valuePop(ctxt);
5178 if (arg == NULL)
5179 XP_ERROR(XPATH_INVALID_OPERAND);
5180 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005181 xmlXPathFreeObject(arg);
5182
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005183 CAST_TO_NUMBER;
5184 CHECK_TYPE(XPATH_NUMBER);
5185 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005186}
5187
5188/**
5189 * xmlXPathMultValues:
5190 * @ctxt: the XPath Parser context
5191 *
5192 * Implement the multiply operation on XPath objects:
5193 * The numeric operators convert their operands to numbers as if
5194 * by calling the number function.
5195 */
5196void
5197xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5198 xmlXPathObjectPtr arg;
5199 double val;
5200
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005201 arg = valuePop(ctxt);
5202 if (arg == NULL)
5203 XP_ERROR(XPATH_INVALID_OPERAND);
5204 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005205 xmlXPathFreeObject(arg);
5206
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005207 CAST_TO_NUMBER;
5208 CHECK_TYPE(XPATH_NUMBER);
5209 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005210}
5211
5212/**
5213 * xmlXPathDivValues:
5214 * @ctxt: the XPath Parser context
5215 *
5216 * Implement the div operation on XPath objects @arg1 / @arg2:
5217 * The numeric operators convert their operands to numbers as if
5218 * by calling the number function.
5219 */
5220void
5221xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5222 xmlXPathObjectPtr arg;
5223 double val;
5224
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005225 arg = valuePop(ctxt);
5226 if (arg == NULL)
5227 XP_ERROR(XPATH_INVALID_OPERAND);
5228 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005229 xmlXPathFreeObject(arg);
5230
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005231 CAST_TO_NUMBER;
5232 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005233 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5234 ctxt->value->floatval = xmlXPathNAN;
5235 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005236 if (ctxt->value->floatval == 0)
5237 ctxt->value->floatval = xmlXPathNAN;
5238 else if (ctxt->value->floatval > 0)
5239 ctxt->value->floatval = xmlXPathNINF;
5240 else if (ctxt->value->floatval < 0)
5241 ctxt->value->floatval = xmlXPathPINF;
5242 }
5243 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005244 if (ctxt->value->floatval == 0)
5245 ctxt->value->floatval = xmlXPathNAN;
5246 else if (ctxt->value->floatval > 0)
5247 ctxt->value->floatval = xmlXPathPINF;
5248 else if (ctxt->value->floatval < 0)
5249 ctxt->value->floatval = xmlXPathNINF;
5250 } else
5251 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005252}
5253
5254/**
5255 * xmlXPathModValues:
5256 * @ctxt: the XPath Parser context
5257 *
5258 * Implement the mod operation on XPath objects: @arg1 / @arg2
5259 * The numeric operators convert their operands to numbers as if
5260 * by calling the number function.
5261 */
5262void
5263xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5264 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005265 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005266
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005267 arg = valuePop(ctxt);
5268 if (arg == NULL)
5269 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005270 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005271 xmlXPathFreeObject(arg);
5272
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005273 CAST_TO_NUMBER;
5274 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005275 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005276 if (arg2 == 0)
5277 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005278 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005279 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005280 }
Owen Taylor3473f882001-02-23 17:55:21 +00005281}
5282
5283/************************************************************************
5284 * *
5285 * The traversal functions *
5286 * *
5287 ************************************************************************/
5288
Owen Taylor3473f882001-02-23 17:55:21 +00005289/*
5290 * A traversal function enumerates nodes along an axis.
5291 * Initially it must be called with NULL, and it indicates
5292 * termination on the axis by returning NULL.
5293 */
5294typedef xmlNodePtr (*xmlXPathTraversalFunction)
5295 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5296
5297/**
5298 * xmlXPathNextSelf:
5299 * @ctxt: the XPath Parser context
5300 * @cur: the current node in the traversal
5301 *
5302 * Traversal function for the "self" direction
5303 * The self axis contains just the context node itself
5304 *
5305 * Returns the next element following that axis
5306 */
5307xmlNodePtr
5308xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5309 if (cur == NULL)
5310 return(ctxt->context->node);
5311 return(NULL);
5312}
5313
5314/**
5315 * xmlXPathNextChild:
5316 * @ctxt: the XPath Parser context
5317 * @cur: the current node in the traversal
5318 *
5319 * Traversal function for the "child" direction
5320 * The child axis contains the children of the context node in document order.
5321 *
5322 * Returns the next element following that axis
5323 */
5324xmlNodePtr
5325xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5326 if (cur == NULL) {
5327 if (ctxt->context->node == NULL) return(NULL);
5328 switch (ctxt->context->node->type) {
5329 case XML_ELEMENT_NODE:
5330 case XML_TEXT_NODE:
5331 case XML_CDATA_SECTION_NODE:
5332 case XML_ENTITY_REF_NODE:
5333 case XML_ENTITY_NODE:
5334 case XML_PI_NODE:
5335 case XML_COMMENT_NODE:
5336 case XML_NOTATION_NODE:
5337 case XML_DTD_NODE:
5338 return(ctxt->context->node->children);
5339 case XML_DOCUMENT_NODE:
5340 case XML_DOCUMENT_TYPE_NODE:
5341 case XML_DOCUMENT_FRAG_NODE:
5342 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005343#ifdef LIBXML_DOCB_ENABLED
5344 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005345#endif
5346 return(((xmlDocPtr) ctxt->context->node)->children);
5347 case XML_ELEMENT_DECL:
5348 case XML_ATTRIBUTE_DECL:
5349 case XML_ENTITY_DECL:
5350 case XML_ATTRIBUTE_NODE:
5351 case XML_NAMESPACE_DECL:
5352 case XML_XINCLUDE_START:
5353 case XML_XINCLUDE_END:
5354 return(NULL);
5355 }
5356 return(NULL);
5357 }
5358 if ((cur->type == XML_DOCUMENT_NODE) ||
5359 (cur->type == XML_HTML_DOCUMENT_NODE))
5360 return(NULL);
5361 return(cur->next);
5362}
5363
5364/**
5365 * xmlXPathNextDescendant:
5366 * @ctxt: the XPath Parser context
5367 * @cur: the current node in the traversal
5368 *
5369 * Traversal function for the "descendant" direction
5370 * the descendant axis contains the descendants of the context node in document
5371 * order; a descendant is a child or a child of a child and so on.
5372 *
5373 * Returns the next element following that axis
5374 */
5375xmlNodePtr
5376xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5377 if (cur == NULL) {
5378 if (ctxt->context->node == NULL)
5379 return(NULL);
5380 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5381 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5382 return(NULL);
5383
5384 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5385 return(ctxt->context->doc->children);
5386 return(ctxt->context->node->children);
5387 }
5388
Daniel Veillard567e1b42001-08-01 15:53:47 +00005389 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005390 /*
5391 * Do not descend on entities declarations
5392 */
5393 if (cur->children->type != XML_ENTITY_DECL) {
5394 cur = cur->children;
5395 /*
5396 * Skip DTDs
5397 */
5398 if (cur->type != XML_DTD_NODE)
5399 return(cur);
5400 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005401 }
5402
5403 if (cur == ctxt->context->node) return(NULL);
5404
Daniel Veillard68e9e742002-11-16 15:35:11 +00005405 while (cur->next != NULL) {
5406 cur = cur->next;
5407 if ((cur->type != XML_ENTITY_DECL) &&
5408 (cur->type != XML_DTD_NODE))
5409 return(cur);
5410 }
Owen Taylor3473f882001-02-23 17:55:21 +00005411
5412 do {
5413 cur = cur->parent;
5414 if (cur == NULL) return(NULL);
5415 if (cur == ctxt->context->node) return(NULL);
5416 if (cur->next != NULL) {
5417 cur = cur->next;
5418 return(cur);
5419 }
5420 } while (cur != NULL);
5421 return(cur);
5422}
5423
5424/**
5425 * xmlXPathNextDescendantOrSelf:
5426 * @ctxt: the XPath Parser context
5427 * @cur: the current node in the traversal
5428 *
5429 * Traversal function for the "descendant-or-self" direction
5430 * the descendant-or-self axis contains the context node and the descendants
5431 * of the context node in document order; thus the context node is the first
5432 * node on the axis, and the first child of the context node is the second node
5433 * on the axis
5434 *
5435 * Returns the next element following that axis
5436 */
5437xmlNodePtr
5438xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5439 if (cur == NULL) {
5440 if (ctxt->context->node == NULL)
5441 return(NULL);
5442 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5443 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5444 return(NULL);
5445 return(ctxt->context->node);
5446 }
5447
5448 return(xmlXPathNextDescendant(ctxt, cur));
5449}
5450
5451/**
5452 * xmlXPathNextParent:
5453 * @ctxt: the XPath Parser context
5454 * @cur: the current node in the traversal
5455 *
5456 * Traversal function for the "parent" direction
5457 * The parent axis contains the parent of the context node, if there is one.
5458 *
5459 * Returns the next element following that axis
5460 */
5461xmlNodePtr
5462xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5463 /*
5464 * the parent of an attribute or namespace node is the element
5465 * to which the attribute or namespace node is attached
5466 * Namespace handling !!!
5467 */
5468 if (cur == NULL) {
5469 if (ctxt->context->node == NULL) return(NULL);
5470 switch (ctxt->context->node->type) {
5471 case XML_ELEMENT_NODE:
5472 case XML_TEXT_NODE:
5473 case XML_CDATA_SECTION_NODE:
5474 case XML_ENTITY_REF_NODE:
5475 case XML_ENTITY_NODE:
5476 case XML_PI_NODE:
5477 case XML_COMMENT_NODE:
5478 case XML_NOTATION_NODE:
5479 case XML_DTD_NODE:
5480 case XML_ELEMENT_DECL:
5481 case XML_ATTRIBUTE_DECL:
5482 case XML_XINCLUDE_START:
5483 case XML_XINCLUDE_END:
5484 case XML_ENTITY_DECL:
5485 if (ctxt->context->node->parent == NULL)
5486 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005487 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005488 ((ctxt->context->node->parent->name[0] == ' ') ||
5489 (xmlStrEqual(ctxt->context->node->parent->name,
5490 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005491 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005492 return(ctxt->context->node->parent);
5493 case XML_ATTRIBUTE_NODE: {
5494 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5495
5496 return(att->parent);
5497 }
5498 case XML_DOCUMENT_NODE:
5499 case XML_DOCUMENT_TYPE_NODE:
5500 case XML_DOCUMENT_FRAG_NODE:
5501 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005502#ifdef LIBXML_DOCB_ENABLED
5503 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005504#endif
5505 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005506 case XML_NAMESPACE_DECL: {
5507 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5508
5509 if ((ns->next != NULL) &&
5510 (ns->next->type != XML_NAMESPACE_DECL))
5511 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005512 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005513 }
Owen Taylor3473f882001-02-23 17:55:21 +00005514 }
5515 }
5516 return(NULL);
5517}
5518
5519/**
5520 * xmlXPathNextAncestor:
5521 * @ctxt: the XPath Parser context
5522 * @cur: the current node in the traversal
5523 *
5524 * Traversal function for the "ancestor" direction
5525 * the ancestor axis contains the ancestors of the context node; the ancestors
5526 * of the context node consist of the parent of context node and the parent's
5527 * parent and so on; the nodes are ordered in reverse document order; thus the
5528 * parent is the first node on the axis, and the parent's parent is the second
5529 * node on the axis
5530 *
5531 * Returns the next element following that axis
5532 */
5533xmlNodePtr
5534xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5535 /*
5536 * the parent of an attribute or namespace node is the element
5537 * to which the attribute or namespace node is attached
5538 * !!!!!!!!!!!!!
5539 */
5540 if (cur == NULL) {
5541 if (ctxt->context->node == NULL) return(NULL);
5542 switch (ctxt->context->node->type) {
5543 case XML_ELEMENT_NODE:
5544 case XML_TEXT_NODE:
5545 case XML_CDATA_SECTION_NODE:
5546 case XML_ENTITY_REF_NODE:
5547 case XML_ENTITY_NODE:
5548 case XML_PI_NODE:
5549 case XML_COMMENT_NODE:
5550 case XML_DTD_NODE:
5551 case XML_ELEMENT_DECL:
5552 case XML_ATTRIBUTE_DECL:
5553 case XML_ENTITY_DECL:
5554 case XML_NOTATION_NODE:
5555 case XML_XINCLUDE_START:
5556 case XML_XINCLUDE_END:
5557 if (ctxt->context->node->parent == NULL)
5558 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005559 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005560 ((ctxt->context->node->parent->name[0] == ' ') ||
5561 (xmlStrEqual(ctxt->context->node->parent->name,
5562 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005563 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005564 return(ctxt->context->node->parent);
5565 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005566 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005567
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005568 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005569 }
5570 case XML_DOCUMENT_NODE:
5571 case XML_DOCUMENT_TYPE_NODE:
5572 case XML_DOCUMENT_FRAG_NODE:
5573 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005574#ifdef LIBXML_DOCB_ENABLED
5575 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005576#endif
5577 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005578 case XML_NAMESPACE_DECL: {
5579 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5580
5581 if ((ns->next != NULL) &&
5582 (ns->next->type != XML_NAMESPACE_DECL))
5583 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005584 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005585 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005586 }
Owen Taylor3473f882001-02-23 17:55:21 +00005587 }
5588 return(NULL);
5589 }
5590 if (cur == ctxt->context->doc->children)
5591 return((xmlNodePtr) ctxt->context->doc);
5592 if (cur == (xmlNodePtr) ctxt->context->doc)
5593 return(NULL);
5594 switch (cur->type) {
5595 case XML_ELEMENT_NODE:
5596 case XML_TEXT_NODE:
5597 case XML_CDATA_SECTION_NODE:
5598 case XML_ENTITY_REF_NODE:
5599 case XML_ENTITY_NODE:
5600 case XML_PI_NODE:
5601 case XML_COMMENT_NODE:
5602 case XML_NOTATION_NODE:
5603 case XML_DTD_NODE:
5604 case XML_ELEMENT_DECL:
5605 case XML_ATTRIBUTE_DECL:
5606 case XML_ENTITY_DECL:
5607 case XML_XINCLUDE_START:
5608 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005609 if (cur->parent == NULL)
5610 return(NULL);
5611 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005612 ((cur->parent->name[0] == ' ') ||
5613 (xmlStrEqual(cur->parent->name,
5614 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005615 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005616 return(cur->parent);
5617 case XML_ATTRIBUTE_NODE: {
5618 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5619
5620 return(att->parent);
5621 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005622 case XML_NAMESPACE_DECL: {
5623 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5624
5625 if ((ns->next != NULL) &&
5626 (ns->next->type != XML_NAMESPACE_DECL))
5627 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005628 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005629 return(NULL);
5630 }
Owen Taylor3473f882001-02-23 17:55:21 +00005631 case XML_DOCUMENT_NODE:
5632 case XML_DOCUMENT_TYPE_NODE:
5633 case XML_DOCUMENT_FRAG_NODE:
5634 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005635#ifdef LIBXML_DOCB_ENABLED
5636 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005637#endif
5638 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005639 }
5640 return(NULL);
5641}
5642
5643/**
5644 * xmlXPathNextAncestorOrSelf:
5645 * @ctxt: the XPath Parser context
5646 * @cur: the current node in the traversal
5647 *
5648 * Traversal function for the "ancestor-or-self" direction
5649 * he ancestor-or-self axis contains the context node and ancestors of
5650 * the context node in reverse document order; thus the context node is
5651 * the first node on the axis, and the context node's parent the second;
5652 * parent here is defined the same as with the parent axis.
5653 *
5654 * Returns the next element following that axis
5655 */
5656xmlNodePtr
5657xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5658 if (cur == NULL)
5659 return(ctxt->context->node);
5660 return(xmlXPathNextAncestor(ctxt, cur));
5661}
5662
5663/**
5664 * xmlXPathNextFollowingSibling:
5665 * @ctxt: the XPath Parser context
5666 * @cur: the current node in the traversal
5667 *
5668 * Traversal function for the "following-sibling" direction
5669 * The following-sibling axis contains the following siblings of the context
5670 * node in document order.
5671 *
5672 * Returns the next element following that axis
5673 */
5674xmlNodePtr
5675xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5676 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5677 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5678 return(NULL);
5679 if (cur == (xmlNodePtr) ctxt->context->doc)
5680 return(NULL);
5681 if (cur == NULL)
5682 return(ctxt->context->node->next);
5683 return(cur->next);
5684}
5685
5686/**
5687 * xmlXPathNextPrecedingSibling:
5688 * @ctxt: the XPath Parser context
5689 * @cur: the current node in the traversal
5690 *
5691 * Traversal function for the "preceding-sibling" direction
5692 * The preceding-sibling axis contains the preceding siblings of the context
5693 * node in reverse document order; the first preceding sibling is first on the
5694 * axis; the sibling preceding that node is the second on the axis and so on.
5695 *
5696 * Returns the next element following that axis
5697 */
5698xmlNodePtr
5699xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5700 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5701 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5702 return(NULL);
5703 if (cur == (xmlNodePtr) ctxt->context->doc)
5704 return(NULL);
5705 if (cur == NULL)
5706 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005707 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5708 cur = cur->prev;
5709 if (cur == NULL)
5710 return(ctxt->context->node->prev);
5711 }
Owen Taylor3473f882001-02-23 17:55:21 +00005712 return(cur->prev);
5713}
5714
5715/**
5716 * xmlXPathNextFollowing:
5717 * @ctxt: the XPath Parser context
5718 * @cur: the current node in the traversal
5719 *
5720 * Traversal function for the "following" direction
5721 * The following axis contains all nodes in the same document as the context
5722 * node that are after the context node in document order, excluding any
5723 * descendants and excluding attribute nodes and namespace nodes; the nodes
5724 * are ordered in document order
5725 *
5726 * Returns the next element following that axis
5727 */
5728xmlNodePtr
5729xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5730 if (cur != NULL && cur->children != NULL)
5731 return cur->children ;
5732 if (cur == NULL) cur = ctxt->context->node;
5733 if (cur == NULL) return(NULL) ; /* ERROR */
5734 if (cur->next != NULL) return(cur->next) ;
5735 do {
5736 cur = cur->parent;
5737 if (cur == NULL) return(NULL);
5738 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5739 if (cur->next != NULL) return(cur->next);
5740 } while (cur != NULL);
5741 return(cur);
5742}
5743
5744/*
5745 * xmlXPathIsAncestor:
5746 * @ancestor: the ancestor node
5747 * @node: the current node
5748 *
5749 * Check that @ancestor is a @node's ancestor
5750 *
5751 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5752 */
5753static int
5754xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5755 if ((ancestor == NULL) || (node == NULL)) return(0);
5756 /* nodes need to be in the same document */
5757 if (ancestor->doc != node->doc) return(0);
5758 /* avoid searching if ancestor or node is the root node */
5759 if (ancestor == (xmlNodePtr) node->doc) return(1);
5760 if (node == (xmlNodePtr) ancestor->doc) return(0);
5761 while (node->parent != NULL) {
5762 if (node->parent == ancestor)
5763 return(1);
5764 node = node->parent;
5765 }
5766 return(0);
5767}
5768
5769/**
5770 * xmlXPathNextPreceding:
5771 * @ctxt: the XPath Parser context
5772 * @cur: the current node in the traversal
5773 *
5774 * Traversal function for the "preceding" direction
5775 * the preceding axis contains all nodes in the same document as the context
5776 * node that are before the context node in document order, excluding any
5777 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5778 * ordered in reverse document order
5779 *
5780 * Returns the next element following that axis
5781 */
5782xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005783xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5784{
Owen Taylor3473f882001-02-23 17:55:21 +00005785 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005786 cur = ctxt->context->node;
5787 if (cur == NULL)
5788 return (NULL);
5789 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5790 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005791 do {
5792 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005793 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5794 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005795 }
5796
5797 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005798 if (cur == NULL)
5799 return (NULL);
5800 if (cur == ctxt->context->doc->children)
5801 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005802 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005803 return (cur);
5804}
5805
5806/**
5807 * xmlXPathNextPrecedingInternal:
5808 * @ctxt: the XPath Parser context
5809 * @cur: the current node in the traversal
5810 *
5811 * Traversal function for the "preceding" direction
5812 * the preceding axis contains all nodes in the same document as the context
5813 * node that are before the context node in document order, excluding any
5814 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5815 * ordered in reverse document order
5816 * This is a faster implementation but internal only since it requires a
5817 * state kept in the parser context: ctxt->ancestor.
5818 *
5819 * Returns the next element following that axis
5820 */
5821static xmlNodePtr
5822xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5823 xmlNodePtr cur)
5824{
5825 if (cur == NULL) {
5826 cur = ctxt->context->node;
5827 if (cur == NULL)
5828 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005829 if (cur->type == XML_NAMESPACE_DECL)
5830 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005831 ctxt->ancestor = cur->parent;
5832 }
5833 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5834 cur = cur->prev;
5835 while (cur->prev == NULL) {
5836 cur = cur->parent;
5837 if (cur == NULL)
5838 return (NULL);
5839 if (cur == ctxt->context->doc->children)
5840 return (NULL);
5841 if (cur != ctxt->ancestor)
5842 return (cur);
5843 ctxt->ancestor = cur->parent;
5844 }
5845 cur = cur->prev;
5846 while (cur->last != NULL)
5847 cur = cur->last;
5848 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005849}
5850
5851/**
5852 * xmlXPathNextNamespace:
5853 * @ctxt: the XPath Parser context
5854 * @cur: the current attribute in the traversal
5855 *
5856 * Traversal function for the "namespace" direction
5857 * the namespace axis contains the namespace nodes of the context node;
5858 * the order of nodes on this axis is implementation-defined; the axis will
5859 * be empty unless the context node is an element
5860 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005861 * We keep the XML namespace node at the end of the list.
5862 *
Owen Taylor3473f882001-02-23 17:55:21 +00005863 * Returns the next element following that axis
5864 */
5865xmlNodePtr
5866xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5867 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005868 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005869 if (ctxt->context->tmpNsList != NULL)
5870 xmlFree(ctxt->context->tmpNsList);
5871 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005872 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005873 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005874 if (ctxt->context->tmpNsList != NULL) {
5875 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5876 ctxt->context->tmpNsNr++;
5877 }
5878 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005879 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005880 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005881 if (ctxt->context->tmpNsNr > 0) {
5882 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5883 } else {
5884 if (ctxt->context->tmpNsList != NULL)
5885 xmlFree(ctxt->context->tmpNsList);
5886 ctxt->context->tmpNsList = NULL;
5887 return(NULL);
5888 }
Owen Taylor3473f882001-02-23 17:55:21 +00005889}
5890
5891/**
5892 * xmlXPathNextAttribute:
5893 * @ctxt: the XPath Parser context
5894 * @cur: the current attribute in the traversal
5895 *
5896 * Traversal function for the "attribute" direction
5897 * TODO: support DTD inherited default attributes
5898 *
5899 * Returns the next element following that axis
5900 */
5901xmlNodePtr
5902xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005903 if (ctxt->context->node == NULL)
5904 return(NULL);
5905 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5906 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005907 if (cur == NULL) {
5908 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5909 return(NULL);
5910 return((xmlNodePtr)ctxt->context->node->properties);
5911 }
5912 return((xmlNodePtr)cur->next);
5913}
5914
5915/************************************************************************
5916 * *
5917 * NodeTest Functions *
5918 * *
5919 ************************************************************************/
5920
Owen Taylor3473f882001-02-23 17:55:21 +00005921#define IS_FUNCTION 200
5922
Owen Taylor3473f882001-02-23 17:55:21 +00005923
5924/************************************************************************
5925 * *
5926 * Implicit tree core function library *
5927 * *
5928 ************************************************************************/
5929
5930/**
5931 * xmlXPathRoot:
5932 * @ctxt: the XPath Parser context
5933 *
5934 * Initialize the context to the root of the document
5935 */
5936void
5937xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5938 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5939 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5940}
5941
5942/************************************************************************
5943 * *
5944 * The explicit core function library *
5945 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5946 * *
5947 ************************************************************************/
5948
5949
5950/**
5951 * xmlXPathLastFunction:
5952 * @ctxt: the XPath Parser context
5953 * @nargs: the number of arguments
5954 *
5955 * Implement the last() XPath function
5956 * number last()
5957 * The last function returns the number of nodes in the context node list.
5958 */
5959void
5960xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5961 CHECK_ARITY(0);
5962 if (ctxt->context->contextSize >= 0) {
5963 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5964#ifdef DEBUG_EXPR
5965 xmlGenericError(xmlGenericErrorContext,
5966 "last() : %d\n", ctxt->context->contextSize);
5967#endif
5968 } else {
5969 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5970 }
5971}
5972
5973/**
5974 * xmlXPathPositionFunction:
5975 * @ctxt: the XPath Parser context
5976 * @nargs: the number of arguments
5977 *
5978 * Implement the position() XPath function
5979 * number position()
5980 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005981 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005982 * will be equal to last().
5983 */
5984void
5985xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5986 CHECK_ARITY(0);
5987 if (ctxt->context->proximityPosition >= 0) {
5988 valuePush(ctxt,
5989 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5990#ifdef DEBUG_EXPR
5991 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5992 ctxt->context->proximityPosition);
5993#endif
5994 } else {
5995 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5996 }
5997}
5998
5999/**
6000 * xmlXPathCountFunction:
6001 * @ctxt: the XPath Parser context
6002 * @nargs: the number of arguments
6003 *
6004 * Implement the count() XPath function
6005 * number count(node-set)
6006 */
6007void
6008xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6009 xmlXPathObjectPtr cur;
6010
6011 CHECK_ARITY(1);
6012 if ((ctxt->value == NULL) ||
6013 ((ctxt->value->type != XPATH_NODESET) &&
6014 (ctxt->value->type != XPATH_XSLT_TREE)))
6015 XP_ERROR(XPATH_INVALID_TYPE);
6016 cur = valuePop(ctxt);
6017
Daniel Veillard911f49a2001-04-07 15:39:35 +00006018 if ((cur == NULL) || (cur->nodesetval == NULL))
6019 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006020 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006021 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006022 } else {
6023 if ((cur->nodesetval->nodeNr != 1) ||
6024 (cur->nodesetval->nodeTab == NULL)) {
6025 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6026 } else {
6027 xmlNodePtr tmp;
6028 int i = 0;
6029
6030 tmp = cur->nodesetval->nodeTab[0];
6031 if (tmp != NULL) {
6032 tmp = tmp->children;
6033 while (tmp != NULL) {
6034 tmp = tmp->next;
6035 i++;
6036 }
6037 }
6038 valuePush(ctxt, xmlXPathNewFloat((double) i));
6039 }
6040 }
Owen Taylor3473f882001-02-23 17:55:21 +00006041 xmlXPathFreeObject(cur);
6042}
6043
6044/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006045 * xmlXPathGetElementsByIds:
6046 * @doc: the document
6047 * @ids: a whitespace separated list of IDs
6048 *
6049 * Selects elements by their unique ID.
6050 *
6051 * Returns a node-set of selected elements.
6052 */
6053static xmlNodeSetPtr
6054xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6055 xmlNodeSetPtr ret;
6056 const xmlChar *cur = ids;
6057 xmlChar *ID;
6058 xmlAttrPtr attr;
6059 xmlNodePtr elem = NULL;
6060
Daniel Veillard7a985a12003-07-06 17:57:42 +00006061 if (ids == NULL) return(NULL);
6062
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006063 ret = xmlXPathNodeSetCreate(NULL);
6064
William M. Brack76e95df2003-10-18 16:20:14 +00006065 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006066 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006067 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006068 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006069
6070 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006071 if (ID != NULL) {
6072 if (xmlValidateNCName(ID, 1) == 0) {
6073 attr = xmlGetID(doc, ID);
6074 if (attr != NULL) {
6075 if (attr->type == XML_ATTRIBUTE_NODE)
6076 elem = attr->parent;
6077 else if (attr->type == XML_ELEMENT_NODE)
6078 elem = (xmlNodePtr) attr;
6079 else
6080 elem = NULL;
6081 if (elem != NULL)
6082 xmlXPathNodeSetAdd(ret, elem);
6083 }
6084 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006085 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006086 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006087
William M. Brack76e95df2003-10-18 16:20:14 +00006088 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006089 ids = cur;
6090 }
6091 return(ret);
6092}
6093
6094/**
Owen Taylor3473f882001-02-23 17:55:21 +00006095 * xmlXPathIdFunction:
6096 * @ctxt: the XPath Parser context
6097 * @nargs: the number of arguments
6098 *
6099 * Implement the id() XPath function
6100 * node-set id(object)
6101 * The id function selects elements by their unique ID
6102 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6103 * then the result is the union of the result of applying id to the
6104 * string value of each of the nodes in the argument node-set. When the
6105 * argument to id is of any other type, the argument is converted to a
6106 * string as if by a call to the string function; the string is split
6107 * into a whitespace-separated list of tokens (whitespace is any sequence
6108 * of characters matching the production S); the result is a node-set
6109 * containing the elements in the same document as the context node that
6110 * have a unique ID equal to any of the tokens in the list.
6111 */
6112void
6113xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006114 xmlChar *tokens;
6115 xmlNodeSetPtr ret;
6116 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006117
6118 CHECK_ARITY(1);
6119 obj = valuePop(ctxt);
6120 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006121 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006122 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006123 int i;
6124
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006125 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006126
Daniel Veillard911f49a2001-04-07 15:39:35 +00006127 if (obj->nodesetval != NULL) {
6128 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006129 tokens =
6130 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6131 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6132 ret = xmlXPathNodeSetMerge(ret, ns);
6133 xmlXPathFreeNodeSet(ns);
6134 if (tokens != NULL)
6135 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006136 }
Owen Taylor3473f882001-02-23 17:55:21 +00006137 }
6138
6139 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006140 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006141 return;
6142 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006143 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006144
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006145 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6146 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006147
Owen Taylor3473f882001-02-23 17:55:21 +00006148 xmlXPathFreeObject(obj);
6149 return;
6150}
6151
6152/**
6153 * xmlXPathLocalNameFunction:
6154 * @ctxt: the XPath Parser context
6155 * @nargs: the number of arguments
6156 *
6157 * Implement the local-name() XPath function
6158 * string local-name(node-set?)
6159 * The local-name function returns a string containing the local part
6160 * of the name of the node in the argument node-set that is first in
6161 * document order. If the node-set is empty or the first node has no
6162 * name, an empty string is returned. If the argument is omitted it
6163 * defaults to the context node.
6164 */
6165void
6166xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6167 xmlXPathObjectPtr cur;
6168
6169 if (nargs == 0) {
6170 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6171 nargs = 1;
6172 }
6173
6174 CHECK_ARITY(1);
6175 if ((ctxt->value == NULL) ||
6176 ((ctxt->value->type != XPATH_NODESET) &&
6177 (ctxt->value->type != XPATH_XSLT_TREE)))
6178 XP_ERROR(XPATH_INVALID_TYPE);
6179 cur = valuePop(ctxt);
6180
Daniel Veillard911f49a2001-04-07 15:39:35 +00006181 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006182 valuePush(ctxt, xmlXPathNewCString(""));
6183 } else {
6184 int i = 0; /* Should be first in document order !!!!! */
6185 switch (cur->nodesetval->nodeTab[i]->type) {
6186 case XML_ELEMENT_NODE:
6187 case XML_ATTRIBUTE_NODE:
6188 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006189 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6190 valuePush(ctxt, xmlXPathNewCString(""));
6191 else
6192 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006193 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6194 break;
6195 case XML_NAMESPACE_DECL:
6196 valuePush(ctxt, xmlXPathNewString(
6197 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6198 break;
6199 default:
6200 valuePush(ctxt, xmlXPathNewCString(""));
6201 }
6202 }
6203 xmlXPathFreeObject(cur);
6204}
6205
6206/**
6207 * xmlXPathNamespaceURIFunction:
6208 * @ctxt: the XPath Parser context
6209 * @nargs: the number of arguments
6210 *
6211 * Implement the namespace-uri() XPath function
6212 * string namespace-uri(node-set?)
6213 * The namespace-uri function returns a string containing the
6214 * namespace URI of the expanded name of the node in the argument
6215 * node-set that is first in document order. If the node-set is empty,
6216 * the first node has no name, or the expanded name has no namespace
6217 * URI, an empty string is returned. If the argument is omitted it
6218 * defaults to the context node.
6219 */
6220void
6221xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6222 xmlXPathObjectPtr cur;
6223
6224 if (nargs == 0) {
6225 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6226 nargs = 1;
6227 }
6228 CHECK_ARITY(1);
6229 if ((ctxt->value == NULL) ||
6230 ((ctxt->value->type != XPATH_NODESET) &&
6231 (ctxt->value->type != XPATH_XSLT_TREE)))
6232 XP_ERROR(XPATH_INVALID_TYPE);
6233 cur = valuePop(ctxt);
6234
Daniel Veillard911f49a2001-04-07 15:39:35 +00006235 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006236 valuePush(ctxt, xmlXPathNewCString(""));
6237 } else {
6238 int i = 0; /* Should be first in document order !!!!! */
6239 switch (cur->nodesetval->nodeTab[i]->type) {
6240 case XML_ELEMENT_NODE:
6241 case XML_ATTRIBUTE_NODE:
6242 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6243 valuePush(ctxt, xmlXPathNewCString(""));
6244 else
6245 valuePush(ctxt, xmlXPathNewString(
6246 cur->nodesetval->nodeTab[i]->ns->href));
6247 break;
6248 default:
6249 valuePush(ctxt, xmlXPathNewCString(""));
6250 }
6251 }
6252 xmlXPathFreeObject(cur);
6253}
6254
6255/**
6256 * xmlXPathNameFunction:
6257 * @ctxt: the XPath Parser context
6258 * @nargs: the number of arguments
6259 *
6260 * Implement the name() XPath function
6261 * string name(node-set?)
6262 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006263 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006264 * order. The QName must represent the name with respect to the namespace
6265 * declarations in effect on the node whose name is being represented.
6266 * Typically, this will be the form in which the name occurred in the XML
6267 * source. This need not be the case if there are namespace declarations
6268 * in effect on the node that associate multiple prefixes with the same
6269 * namespace. However, an implementation may include information about
6270 * the original prefix in its representation of nodes; in this case, an
6271 * implementation can ensure that the returned string is always the same
6272 * as the QName used in the XML source. If the argument it omitted it
6273 * defaults to the context node.
6274 * Libxml keep the original prefix so the "real qualified name" used is
6275 * returned.
6276 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006277static void
Daniel Veillard04383752001-07-08 14:27:15 +00006278xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6279{
Owen Taylor3473f882001-02-23 17:55:21 +00006280 xmlXPathObjectPtr cur;
6281
6282 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006283 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6284 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006285 }
6286
6287 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006288 if ((ctxt->value == NULL) ||
6289 ((ctxt->value->type != XPATH_NODESET) &&
6290 (ctxt->value->type != XPATH_XSLT_TREE)))
6291 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006292 cur = valuePop(ctxt);
6293
Daniel Veillard911f49a2001-04-07 15:39:35 +00006294 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006295 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006296 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006297 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006298
Daniel Veillard04383752001-07-08 14:27:15 +00006299 switch (cur->nodesetval->nodeTab[i]->type) {
6300 case XML_ELEMENT_NODE:
6301 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006302 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6303 valuePush(ctxt, xmlXPathNewCString(""));
6304 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6305 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006306 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006307 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006308
Daniel Veillard652d8a92003-02-04 19:28:49 +00006309 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006310 xmlChar *fullname;
6311
6312 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6313 cur->nodesetval->nodeTab[i]->ns->prefix,
6314 NULL, 0);
6315 if (fullname == cur->nodesetval->nodeTab[i]->name)
6316 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6317 if (fullname == NULL) {
6318 XP_ERROR(XPATH_MEMORY_ERROR);
6319 }
6320 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006321 }
6322 break;
6323 default:
6324 valuePush(ctxt,
6325 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6326 xmlXPathLocalNameFunction(ctxt, 1);
6327 }
Owen Taylor3473f882001-02-23 17:55:21 +00006328 }
6329 xmlXPathFreeObject(cur);
6330}
6331
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006332
6333/**
Owen Taylor3473f882001-02-23 17:55:21 +00006334 * xmlXPathStringFunction:
6335 * @ctxt: the XPath Parser context
6336 * @nargs: the number of arguments
6337 *
6338 * Implement the string() XPath function
6339 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006340 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006341 * - A node-set is converted to a string by returning the value of
6342 * the node in the node-set that is first in document order.
6343 * If the node-set is empty, an empty string is returned.
6344 * - A number is converted to a string as follows
6345 * + NaN is converted to the string NaN
6346 * + positive zero is converted to the string 0
6347 * + negative zero is converted to the string 0
6348 * + positive infinity is converted to the string Infinity
6349 * + negative infinity is converted to the string -Infinity
6350 * + if the number is an integer, the number is represented in
6351 * decimal form as a Number with no decimal point and no leading
6352 * zeros, preceded by a minus sign (-) if the number is negative
6353 * + otherwise, the number is represented in decimal form as a
6354 * Number including a decimal point with at least one digit
6355 * before the decimal point and at least one digit after the
6356 * decimal point, preceded by a minus sign (-) if the number
6357 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006358 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006359 * before the decimal point; beyond the one required digit
6360 * after the decimal point there must be as many, but only as
6361 * many, more digits as are needed to uniquely distinguish the
6362 * number from all other IEEE 754 numeric values.
6363 * - The boolean false value is converted to the string false.
6364 * The boolean true value is converted to the string true.
6365 *
6366 * If the argument is omitted, it defaults to a node-set with the
6367 * context node as its only member.
6368 */
6369void
6370xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6371 xmlXPathObjectPtr cur;
6372
6373 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006374 valuePush(ctxt,
6375 xmlXPathWrapString(
6376 xmlXPathCastNodeToString(ctxt->context->node)));
6377 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006378 }
6379
6380 CHECK_ARITY(1);
6381 cur = valuePop(ctxt);
6382 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006383 cur = xmlXPathConvertString(cur);
6384 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006385}
6386
6387/**
6388 * xmlXPathStringLengthFunction:
6389 * @ctxt: the XPath Parser context
6390 * @nargs: the number of arguments
6391 *
6392 * Implement the string-length() XPath function
6393 * number string-length(string?)
6394 * The string-length returns the number of characters in the string
6395 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6396 * the context node converted to a string, in other words the value
6397 * of the context node.
6398 */
6399void
6400xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6401 xmlXPathObjectPtr cur;
6402
6403 if (nargs == 0) {
6404 if (ctxt->context->node == NULL) {
6405 valuePush(ctxt, xmlXPathNewFloat(0));
6406 } else {
6407 xmlChar *content;
6408
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006409 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006410 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006411 xmlFree(content);
6412 }
6413 return;
6414 }
6415 CHECK_ARITY(1);
6416 CAST_TO_STRING;
6417 CHECK_TYPE(XPATH_STRING);
6418 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006419 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006420 xmlXPathFreeObject(cur);
6421}
6422
6423/**
6424 * xmlXPathConcatFunction:
6425 * @ctxt: the XPath Parser context
6426 * @nargs: the number of arguments
6427 *
6428 * Implement the concat() XPath function
6429 * string concat(string, string, string*)
6430 * The concat function returns the concatenation of its arguments.
6431 */
6432void
6433xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6434 xmlXPathObjectPtr cur, newobj;
6435 xmlChar *tmp;
6436
6437 if (nargs < 2) {
6438 CHECK_ARITY(2);
6439 }
6440
6441 CAST_TO_STRING;
6442 cur = valuePop(ctxt);
6443 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6444 xmlXPathFreeObject(cur);
6445 return;
6446 }
6447 nargs--;
6448
6449 while (nargs > 0) {
6450 CAST_TO_STRING;
6451 newobj = valuePop(ctxt);
6452 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6453 xmlXPathFreeObject(newobj);
6454 xmlXPathFreeObject(cur);
6455 XP_ERROR(XPATH_INVALID_TYPE);
6456 }
6457 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6458 newobj->stringval = cur->stringval;
6459 cur->stringval = tmp;
6460
6461 xmlXPathFreeObject(newobj);
6462 nargs--;
6463 }
6464 valuePush(ctxt, cur);
6465}
6466
6467/**
6468 * xmlXPathContainsFunction:
6469 * @ctxt: the XPath Parser context
6470 * @nargs: the number of arguments
6471 *
6472 * Implement the contains() XPath function
6473 * boolean contains(string, string)
6474 * The contains function returns true if the first argument string
6475 * contains the second argument string, and otherwise returns false.
6476 */
6477void
6478xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6479 xmlXPathObjectPtr hay, needle;
6480
6481 CHECK_ARITY(2);
6482 CAST_TO_STRING;
6483 CHECK_TYPE(XPATH_STRING);
6484 needle = valuePop(ctxt);
6485 CAST_TO_STRING;
6486 hay = valuePop(ctxt);
6487 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6488 xmlXPathFreeObject(hay);
6489 xmlXPathFreeObject(needle);
6490 XP_ERROR(XPATH_INVALID_TYPE);
6491 }
6492 if (xmlStrstr(hay->stringval, needle->stringval))
6493 valuePush(ctxt, xmlXPathNewBoolean(1));
6494 else
6495 valuePush(ctxt, xmlXPathNewBoolean(0));
6496 xmlXPathFreeObject(hay);
6497 xmlXPathFreeObject(needle);
6498}
6499
6500/**
6501 * xmlXPathStartsWithFunction:
6502 * @ctxt: the XPath Parser context
6503 * @nargs: the number of arguments
6504 *
6505 * Implement the starts-with() XPath function
6506 * boolean starts-with(string, string)
6507 * The starts-with function returns true if the first argument string
6508 * starts with the second argument string, and otherwise returns false.
6509 */
6510void
6511xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6512 xmlXPathObjectPtr hay, needle;
6513 int n;
6514
6515 CHECK_ARITY(2);
6516 CAST_TO_STRING;
6517 CHECK_TYPE(XPATH_STRING);
6518 needle = valuePop(ctxt);
6519 CAST_TO_STRING;
6520 hay = valuePop(ctxt);
6521 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6522 xmlXPathFreeObject(hay);
6523 xmlXPathFreeObject(needle);
6524 XP_ERROR(XPATH_INVALID_TYPE);
6525 }
6526 n = xmlStrlen(needle->stringval);
6527 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6528 valuePush(ctxt, xmlXPathNewBoolean(0));
6529 else
6530 valuePush(ctxt, xmlXPathNewBoolean(1));
6531 xmlXPathFreeObject(hay);
6532 xmlXPathFreeObject(needle);
6533}
6534
6535/**
6536 * xmlXPathSubstringFunction:
6537 * @ctxt: the XPath Parser context
6538 * @nargs: the number of arguments
6539 *
6540 * Implement the substring() XPath function
6541 * string substring(string, number, number?)
6542 * The substring function returns the substring of the first argument
6543 * starting at the position specified in the second argument with
6544 * length specified in the third argument. For example,
6545 * substring("12345",2,3) returns "234". If the third argument is not
6546 * specified, it returns the substring starting at the position specified
6547 * in the second argument and continuing to the end of the string. For
6548 * example, substring("12345",2) returns "2345". More precisely, each
6549 * character in the string (see [3.6 Strings]) is considered to have a
6550 * numeric position: the position of the first character is 1, the position
6551 * of the second character is 2 and so on. The returned substring contains
6552 * those characters for which the position of the character is greater than
6553 * or equal to the second argument and, if the third argument is specified,
6554 * less than the sum of the second and third arguments; the comparisons
6555 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6556 * - substring("12345", 1.5, 2.6) returns "234"
6557 * - substring("12345", 0, 3) returns "12"
6558 * - substring("12345", 0 div 0, 3) returns ""
6559 * - substring("12345", 1, 0 div 0) returns ""
6560 * - substring("12345", -42, 1 div 0) returns "12345"
6561 * - substring("12345", -1 div 0, 1 div 0) returns ""
6562 */
6563void
6564xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6565 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006566 double le=0, in;
6567 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006568 xmlChar *ret;
6569
Owen Taylor3473f882001-02-23 17:55:21 +00006570 if (nargs < 2) {
6571 CHECK_ARITY(2);
6572 }
6573 if (nargs > 3) {
6574 CHECK_ARITY(3);
6575 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006576 /*
6577 * take care of possible last (position) argument
6578 */
Owen Taylor3473f882001-02-23 17:55:21 +00006579 if (nargs == 3) {
6580 CAST_TO_NUMBER;
6581 CHECK_TYPE(XPATH_NUMBER);
6582 len = valuePop(ctxt);
6583 le = len->floatval;
6584 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006585 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006586
Owen Taylor3473f882001-02-23 17:55:21 +00006587 CAST_TO_NUMBER;
6588 CHECK_TYPE(XPATH_NUMBER);
6589 start = valuePop(ctxt);
6590 in = start->floatval;
6591 xmlXPathFreeObject(start);
6592 CAST_TO_STRING;
6593 CHECK_TYPE(XPATH_STRING);
6594 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006595 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006596
Daniel Veillard97ac1312001-05-30 19:14:17 +00006597 /*
6598 * If last pos not present, calculate last position
6599 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006600 if (nargs != 3) {
6601 le = (double)m;
6602 if (in < 1.0)
6603 in = 1.0;
6604 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006605
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006606 /* Need to check for the special cases where either
6607 * the index is NaN, the length is NaN, or both
6608 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006609 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006610 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006611 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006612 * To meet the requirements of the spec, the arguments
6613 * must be converted to integer format before
6614 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006615 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006616 * First we go to integer form, rounding up
6617 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006618 */
6619 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006620 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006621
Daniel Veillard9e412302002-06-10 15:59:44 +00006622 if (xmlXPathIsInf(le) == 1) {
6623 l = m;
6624 if (i < 1)
6625 i = 1;
6626 }
6627 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6628 l = 0;
6629 else {
6630 l = (int) le;
6631 if (((double)l)+0.5 <= le) l++;
6632 }
6633
6634 /* Now we normalize inidices */
6635 i -= 1;
6636 l += i;
6637 if (i < 0)
6638 i = 0;
6639 if (l > m)
6640 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006641
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006642 /* number of chars to copy */
6643 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006644
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006645 ret = xmlUTF8Strsub(str->stringval, i, l);
6646 }
6647 else {
6648 ret = NULL;
6649 }
6650
Owen Taylor3473f882001-02-23 17:55:21 +00006651 if (ret == NULL)
6652 valuePush(ctxt, xmlXPathNewCString(""));
6653 else {
6654 valuePush(ctxt, xmlXPathNewString(ret));
6655 xmlFree(ret);
6656 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006657
Owen Taylor3473f882001-02-23 17:55:21 +00006658 xmlXPathFreeObject(str);
6659}
6660
6661/**
6662 * xmlXPathSubstringBeforeFunction:
6663 * @ctxt: the XPath Parser context
6664 * @nargs: the number of arguments
6665 *
6666 * Implement the substring-before() XPath function
6667 * string substring-before(string, string)
6668 * The substring-before function returns the substring of the first
6669 * argument string that precedes the first occurrence of the second
6670 * argument string in the first argument string, or the empty string
6671 * if the first argument string does not contain the second argument
6672 * string. For example, substring-before("1999/04/01","/") returns 1999.
6673 */
6674void
6675xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6676 xmlXPathObjectPtr str;
6677 xmlXPathObjectPtr find;
6678 xmlBufferPtr target;
6679 const xmlChar *point;
6680 int offset;
6681
6682 CHECK_ARITY(2);
6683 CAST_TO_STRING;
6684 find = valuePop(ctxt);
6685 CAST_TO_STRING;
6686 str = valuePop(ctxt);
6687
6688 target = xmlBufferCreate();
6689 if (target) {
6690 point = xmlStrstr(str->stringval, find->stringval);
6691 if (point) {
6692 offset = (int)(point - str->stringval);
6693 xmlBufferAdd(target, str->stringval, offset);
6694 }
6695 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6696 xmlBufferFree(target);
6697 }
6698
6699 xmlXPathFreeObject(str);
6700 xmlXPathFreeObject(find);
6701}
6702
6703/**
6704 * xmlXPathSubstringAfterFunction:
6705 * @ctxt: the XPath Parser context
6706 * @nargs: the number of arguments
6707 *
6708 * Implement the substring-after() XPath function
6709 * string substring-after(string, string)
6710 * The substring-after function returns the substring of the first
6711 * argument string that follows the first occurrence of the second
6712 * argument string in the first argument string, or the empty stringi
6713 * if the first argument string does not contain the second argument
6714 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6715 * and substring-after("1999/04/01","19") returns 99/04/01.
6716 */
6717void
6718xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6719 xmlXPathObjectPtr str;
6720 xmlXPathObjectPtr find;
6721 xmlBufferPtr target;
6722 const xmlChar *point;
6723 int offset;
6724
6725 CHECK_ARITY(2);
6726 CAST_TO_STRING;
6727 find = valuePop(ctxt);
6728 CAST_TO_STRING;
6729 str = valuePop(ctxt);
6730
6731 target = xmlBufferCreate();
6732 if (target) {
6733 point = xmlStrstr(str->stringval, find->stringval);
6734 if (point) {
6735 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6736 xmlBufferAdd(target, &str->stringval[offset],
6737 xmlStrlen(str->stringval) - offset);
6738 }
6739 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6740 xmlBufferFree(target);
6741 }
6742
6743 xmlXPathFreeObject(str);
6744 xmlXPathFreeObject(find);
6745}
6746
6747/**
6748 * xmlXPathNormalizeFunction:
6749 * @ctxt: the XPath Parser context
6750 * @nargs: the number of arguments
6751 *
6752 * Implement the normalize-space() XPath function
6753 * string normalize-space(string?)
6754 * The normalize-space function returns the argument string with white
6755 * space normalized by stripping leading and trailing whitespace
6756 * and replacing sequences of whitespace characters by a single
6757 * space. Whitespace characters are the same allowed by the S production
6758 * in XML. If the argument is omitted, it defaults to the context
6759 * node converted to a string, in other words the value of the context node.
6760 */
6761void
6762xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6763 xmlXPathObjectPtr obj = NULL;
6764 xmlChar *source = NULL;
6765 xmlBufferPtr target;
6766 xmlChar blank;
6767
6768 if (nargs == 0) {
6769 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006770 valuePush(ctxt,
6771 xmlXPathWrapString(
6772 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006773 nargs = 1;
6774 }
6775
6776 CHECK_ARITY(1);
6777 CAST_TO_STRING;
6778 CHECK_TYPE(XPATH_STRING);
6779 obj = valuePop(ctxt);
6780 source = obj->stringval;
6781
6782 target = xmlBufferCreate();
6783 if (target && source) {
6784
6785 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006786 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006787 source++;
6788
6789 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6790 blank = 0;
6791 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006792 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006793 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006794 } else {
6795 if (blank) {
6796 xmlBufferAdd(target, &blank, 1);
6797 blank = 0;
6798 }
6799 xmlBufferAdd(target, source, 1);
6800 }
6801 source++;
6802 }
6803
6804 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6805 xmlBufferFree(target);
6806 }
6807 xmlXPathFreeObject(obj);
6808}
6809
6810/**
6811 * xmlXPathTranslateFunction:
6812 * @ctxt: the XPath Parser context
6813 * @nargs: the number of arguments
6814 *
6815 * Implement the translate() XPath function
6816 * string translate(string, string, string)
6817 * The translate function returns the first argument string with
6818 * occurrences of characters in the second argument string replaced
6819 * by the character at the corresponding position in the third argument
6820 * string. For example, translate("bar","abc","ABC") returns the string
6821 * BAr. If there is a character in the second argument string with no
6822 * character at a corresponding position in the third argument string
6823 * (because the second argument string is longer than the third argument
6824 * string), then occurrences of that character in the first argument
6825 * string are removed. For example, translate("--aaa--","abc-","ABC")
6826 * returns "AAA". If a character occurs more than once in second
6827 * argument string, then the first occurrence determines the replacement
6828 * character. If the third argument string is longer than the second
6829 * argument string, then excess characters are ignored.
6830 */
6831void
6832xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006833 xmlXPathObjectPtr str;
6834 xmlXPathObjectPtr from;
6835 xmlXPathObjectPtr to;
6836 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006837 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006838 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006839 xmlChar *point;
6840 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006841
Daniel Veillarde043ee12001-04-16 14:08:07 +00006842 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006843
Daniel Veillarde043ee12001-04-16 14:08:07 +00006844 CAST_TO_STRING;
6845 to = valuePop(ctxt);
6846 CAST_TO_STRING;
6847 from = valuePop(ctxt);
6848 CAST_TO_STRING;
6849 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006850
Daniel Veillarde043ee12001-04-16 14:08:07 +00006851 target = xmlBufferCreate();
6852 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006853 max = xmlUTF8Strlen(to->stringval);
6854 for (cptr = str->stringval; (ch=*cptr); ) {
6855 offset = xmlUTF8Strloc(from->stringval, cptr);
6856 if (offset >= 0) {
6857 if (offset < max) {
6858 point = xmlUTF8Strpos(to->stringval, offset);
6859 if (point)
6860 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6861 }
6862 } else
6863 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6864
6865 /* Step to next character in input */
6866 cptr++;
6867 if ( ch & 0x80 ) {
6868 /* if not simple ascii, verify proper format */
6869 if ( (ch & 0xc0) != 0xc0 ) {
6870 xmlGenericError(xmlGenericErrorContext,
6871 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6872 break;
6873 }
6874 /* then skip over remaining bytes for this char */
6875 while ( (ch <<= 1) & 0x80 )
6876 if ( (*cptr++ & 0xc0) != 0x80 ) {
6877 xmlGenericError(xmlGenericErrorContext,
6878 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6879 break;
6880 }
6881 if (ch & 0x80) /* must have had error encountered */
6882 break;
6883 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006884 }
Owen Taylor3473f882001-02-23 17:55:21 +00006885 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006886 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6887 xmlBufferFree(target);
6888 xmlXPathFreeObject(str);
6889 xmlXPathFreeObject(from);
6890 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006891}
6892
6893/**
6894 * xmlXPathBooleanFunction:
6895 * @ctxt: the XPath Parser context
6896 * @nargs: the number of arguments
6897 *
6898 * Implement the boolean() XPath function
6899 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00006900 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006901 * - a number is true if and only if it is neither positive or
6902 * negative zero nor NaN
6903 * - a node-set is true if and only if it is non-empty
6904 * - a string is true if and only if its length is non-zero
6905 */
6906void
6907xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6908 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006909
6910 CHECK_ARITY(1);
6911 cur = valuePop(ctxt);
6912 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006913 cur = xmlXPathConvertBoolean(cur);
6914 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006915}
6916
6917/**
6918 * xmlXPathNotFunction:
6919 * @ctxt: the XPath Parser context
6920 * @nargs: the number of arguments
6921 *
6922 * Implement the not() XPath function
6923 * boolean not(boolean)
6924 * The not function returns true if its argument is false,
6925 * and false otherwise.
6926 */
6927void
6928xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6929 CHECK_ARITY(1);
6930 CAST_TO_BOOLEAN;
6931 CHECK_TYPE(XPATH_BOOLEAN);
6932 ctxt->value->boolval = ! ctxt->value->boolval;
6933}
6934
6935/**
6936 * xmlXPathTrueFunction:
6937 * @ctxt: the XPath Parser context
6938 * @nargs: the number of arguments
6939 *
6940 * Implement the true() XPath function
6941 * boolean true()
6942 */
6943void
6944xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6945 CHECK_ARITY(0);
6946 valuePush(ctxt, xmlXPathNewBoolean(1));
6947}
6948
6949/**
6950 * xmlXPathFalseFunction:
6951 * @ctxt: the XPath Parser context
6952 * @nargs: the number of arguments
6953 *
6954 * Implement the false() XPath function
6955 * boolean false()
6956 */
6957void
6958xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6959 CHECK_ARITY(0);
6960 valuePush(ctxt, xmlXPathNewBoolean(0));
6961}
6962
6963/**
6964 * xmlXPathLangFunction:
6965 * @ctxt: the XPath Parser context
6966 * @nargs: the number of arguments
6967 *
6968 * Implement the lang() XPath function
6969 * boolean lang(string)
6970 * The lang function returns true or false depending on whether the
6971 * language of the context node as specified by xml:lang attributes
6972 * is the same as or is a sublanguage of the language specified by
6973 * the argument string. The language of the context node is determined
6974 * by the value of the xml:lang attribute on the context node, or, if
6975 * the context node has no xml:lang attribute, by the value of the
6976 * xml:lang attribute on the nearest ancestor of the context node that
6977 * has an xml:lang attribute. If there is no such attribute, then lang
6978 * returns false. If there is such an attribute, then lang returns
6979 * true if the attribute value is equal to the argument ignoring case,
6980 * or if there is some suffix starting with - such that the attribute
6981 * value is equal to the argument ignoring that suffix of the attribute
6982 * value and ignoring case.
6983 */
6984void
6985xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6986 xmlXPathObjectPtr val;
6987 const xmlChar *theLang;
6988 const xmlChar *lang;
6989 int ret = 0;
6990 int i;
6991
6992 CHECK_ARITY(1);
6993 CAST_TO_STRING;
6994 CHECK_TYPE(XPATH_STRING);
6995 val = valuePop(ctxt);
6996 lang = val->stringval;
6997 theLang = xmlNodeGetLang(ctxt->context->node);
6998 if ((theLang != NULL) && (lang != NULL)) {
6999 for (i = 0;lang[i] != 0;i++)
7000 if (toupper(lang[i]) != toupper(theLang[i]))
7001 goto not_equal;
7002 ret = 1;
7003 }
7004not_equal:
7005 xmlXPathFreeObject(val);
7006 valuePush(ctxt, xmlXPathNewBoolean(ret));
7007}
7008
7009/**
7010 * xmlXPathNumberFunction:
7011 * @ctxt: the XPath Parser context
7012 * @nargs: the number of arguments
7013 *
7014 * Implement the number() XPath function
7015 * number number(object?)
7016 */
7017void
7018xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7019 xmlXPathObjectPtr cur;
7020 double res;
7021
7022 if (nargs == 0) {
7023 if (ctxt->context->node == NULL) {
7024 valuePush(ctxt, xmlXPathNewFloat(0.0));
7025 } else {
7026 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7027
7028 res = xmlXPathStringEvalNumber(content);
7029 valuePush(ctxt, xmlXPathNewFloat(res));
7030 xmlFree(content);
7031 }
7032 return;
7033 }
7034
7035 CHECK_ARITY(1);
7036 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007037 cur = xmlXPathConvertNumber(cur);
7038 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007039}
7040
7041/**
7042 * xmlXPathSumFunction:
7043 * @ctxt: the XPath Parser context
7044 * @nargs: the number of arguments
7045 *
7046 * Implement the sum() XPath function
7047 * number sum(node-set)
7048 * The sum function returns the sum of the values of the nodes in
7049 * the argument node-set.
7050 */
7051void
7052xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7053 xmlXPathObjectPtr cur;
7054 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007055 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007056
7057 CHECK_ARITY(1);
7058 if ((ctxt->value == NULL) ||
7059 ((ctxt->value->type != XPATH_NODESET) &&
7060 (ctxt->value->type != XPATH_XSLT_TREE)))
7061 XP_ERROR(XPATH_INVALID_TYPE);
7062 cur = valuePop(ctxt);
7063
William M. Brack08171912003-12-29 02:52:11 +00007064 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007065 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7066 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007067 }
7068 }
William M. Brack08171912003-12-29 02:52:11 +00007069 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007070 xmlXPathFreeObject(cur);
7071}
7072
7073/**
7074 * xmlXPathFloorFunction:
7075 * @ctxt: the XPath Parser context
7076 * @nargs: the number of arguments
7077 *
7078 * Implement the floor() XPath function
7079 * number floor(number)
7080 * The floor function returns the largest (closest to positive infinity)
7081 * number that is not greater than the argument and that is an integer.
7082 */
7083void
7084xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007085 double f;
7086
Owen Taylor3473f882001-02-23 17:55:21 +00007087 CHECK_ARITY(1);
7088 CAST_TO_NUMBER;
7089 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007090
7091 f = (double)((int) ctxt->value->floatval);
7092 if (f != ctxt->value->floatval) {
7093 if (ctxt->value->floatval > 0)
7094 ctxt->value->floatval = f;
7095 else
7096 ctxt->value->floatval = f - 1;
7097 }
Owen Taylor3473f882001-02-23 17:55:21 +00007098}
7099
7100/**
7101 * xmlXPathCeilingFunction:
7102 * @ctxt: the XPath Parser context
7103 * @nargs: the number of arguments
7104 *
7105 * Implement the ceiling() XPath function
7106 * number ceiling(number)
7107 * The ceiling function returns the smallest (closest to negative infinity)
7108 * number that is not less than the argument and that is an integer.
7109 */
7110void
7111xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7112 double f;
7113
7114 CHECK_ARITY(1);
7115 CAST_TO_NUMBER;
7116 CHECK_TYPE(XPATH_NUMBER);
7117
7118#if 0
7119 ctxt->value->floatval = ceil(ctxt->value->floatval);
7120#else
7121 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007122 if (f != ctxt->value->floatval) {
7123 if (ctxt->value->floatval > 0)
7124 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007125 else {
7126 if (ctxt->value->floatval < 0 && f == 0)
7127 ctxt->value->floatval = xmlXPathNZERO;
7128 else
7129 ctxt->value->floatval = f;
7130 }
7131
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007132 }
Owen Taylor3473f882001-02-23 17:55:21 +00007133#endif
7134}
7135
7136/**
7137 * xmlXPathRoundFunction:
7138 * @ctxt: the XPath Parser context
7139 * @nargs: the number of arguments
7140 *
7141 * Implement the round() XPath function
7142 * number round(number)
7143 * The round function returns the number that is closest to the
7144 * argument and that is an integer. If there are two such numbers,
7145 * then the one that is even is returned.
7146 */
7147void
7148xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7149 double f;
7150
7151 CHECK_ARITY(1);
7152 CAST_TO_NUMBER;
7153 CHECK_TYPE(XPATH_NUMBER);
7154
Daniel Veillardcda96922001-08-21 10:56:31 +00007155 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7156 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7157 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007158 (ctxt->value->floatval == 0.0))
7159 return;
7160
Owen Taylor3473f882001-02-23 17:55:21 +00007161 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007162 if (ctxt->value->floatval < 0) {
7163 if (ctxt->value->floatval < f - 0.5)
7164 ctxt->value->floatval = f - 1;
7165 else
7166 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007167 if (ctxt->value->floatval == 0)
7168 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007169 } else {
7170 if (ctxt->value->floatval < f + 0.5)
7171 ctxt->value->floatval = f;
7172 else
7173 ctxt->value->floatval = f + 1;
7174 }
Owen Taylor3473f882001-02-23 17:55:21 +00007175}
7176
7177/************************************************************************
7178 * *
7179 * The Parser *
7180 * *
7181 ************************************************************************/
7182
7183/*
William M. Brack08171912003-12-29 02:52:11 +00007184 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007185 * implementation.
7186 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007187static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007188static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007189static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007190static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007191static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7192 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007193
7194/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007195 * xmlXPathCurrentChar:
7196 * @ctxt: the XPath parser context
7197 * @cur: pointer to the beginning of the char
7198 * @len: pointer to the length of the char read
7199 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007200 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007201 * bytes in the input buffer.
7202 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007203 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007204 */
7205
7206static int
7207xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7208 unsigned char c;
7209 unsigned int val;
7210 const xmlChar *cur;
7211
7212 if (ctxt == NULL)
7213 return(0);
7214 cur = ctxt->cur;
7215
7216 /*
7217 * We are supposed to handle UTF8, check it's valid
7218 * From rfc2044: encoding of the Unicode values on UTF-8:
7219 *
7220 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7221 * 0000 0000-0000 007F 0xxxxxxx
7222 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7223 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7224 *
7225 * Check for the 0x110000 limit too
7226 */
7227 c = *cur;
7228 if (c & 0x80) {
7229 if ((cur[1] & 0xc0) != 0x80)
7230 goto encoding_error;
7231 if ((c & 0xe0) == 0xe0) {
7232
7233 if ((cur[2] & 0xc0) != 0x80)
7234 goto encoding_error;
7235 if ((c & 0xf0) == 0xf0) {
7236 if (((c & 0xf8) != 0xf0) ||
7237 ((cur[3] & 0xc0) != 0x80))
7238 goto encoding_error;
7239 /* 4-byte code */
7240 *len = 4;
7241 val = (cur[0] & 0x7) << 18;
7242 val |= (cur[1] & 0x3f) << 12;
7243 val |= (cur[2] & 0x3f) << 6;
7244 val |= cur[3] & 0x3f;
7245 } else {
7246 /* 3-byte code */
7247 *len = 3;
7248 val = (cur[0] & 0xf) << 12;
7249 val |= (cur[1] & 0x3f) << 6;
7250 val |= cur[2] & 0x3f;
7251 }
7252 } else {
7253 /* 2-byte code */
7254 *len = 2;
7255 val = (cur[0] & 0x1f) << 6;
7256 val |= cur[1] & 0x3f;
7257 }
7258 if (!IS_CHAR(val)) {
7259 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7260 }
7261 return(val);
7262 } else {
7263 /* 1-byte code */
7264 *len = 1;
7265 return((int) *cur);
7266 }
7267encoding_error:
7268 /*
William M. Brack08171912003-12-29 02:52:11 +00007269 * If we detect an UTF8 error that probably means that the
7270 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007271 * declaration header. Report the error and switch the encoding
7272 * to ISO-Latin-1 (if you don't like this policy, just declare the
7273 * encoding !)
7274 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007275 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007276 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007277}
7278
7279/**
Owen Taylor3473f882001-02-23 17:55:21 +00007280 * xmlXPathParseNCName:
7281 * @ctxt: the XPath Parser context
7282 *
7283 * parse an XML namespace non qualified name.
7284 *
7285 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7286 *
7287 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7288 * CombiningChar | Extender
7289 *
7290 * Returns the namespace name or NULL
7291 */
7292
7293xmlChar *
7294xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007295 const xmlChar *in;
7296 xmlChar *ret;
7297 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007298
Daniel Veillard2156a562001-04-28 12:24:34 +00007299 /*
7300 * Accelerator for simple ASCII names
7301 */
7302 in = ctxt->cur;
7303 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7304 ((*in >= 0x41) && (*in <= 0x5A)) ||
7305 (*in == '_')) {
7306 in++;
7307 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7308 ((*in >= 0x41) && (*in <= 0x5A)) ||
7309 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007310 (*in == '_') || (*in == '.') ||
7311 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007312 in++;
7313 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7314 (*in == '[') || (*in == ']') || (*in == ':') ||
7315 (*in == '@') || (*in == '*')) {
7316 count = in - ctxt->cur;
7317 if (count == 0)
7318 return(NULL);
7319 ret = xmlStrndup(ctxt->cur, count);
7320 ctxt->cur = in;
7321 return(ret);
7322 }
7323 }
7324 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007325}
7326
Daniel Veillard2156a562001-04-28 12:24:34 +00007327
Owen Taylor3473f882001-02-23 17:55:21 +00007328/**
7329 * xmlXPathParseQName:
7330 * @ctxt: the XPath Parser context
7331 * @prefix: a xmlChar **
7332 *
7333 * parse an XML qualified name
7334 *
7335 * [NS 5] QName ::= (Prefix ':')? LocalPart
7336 *
7337 * [NS 6] Prefix ::= NCName
7338 *
7339 * [NS 7] LocalPart ::= NCName
7340 *
7341 * Returns the function returns the local part, and prefix is updated
7342 * to get the Prefix if any.
7343 */
7344
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007345static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007346xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7347 xmlChar *ret = NULL;
7348
7349 *prefix = NULL;
7350 ret = xmlXPathParseNCName(ctxt);
7351 if (CUR == ':') {
7352 *prefix = ret;
7353 NEXT;
7354 ret = xmlXPathParseNCName(ctxt);
7355 }
7356 return(ret);
7357}
7358
7359/**
7360 * xmlXPathParseName:
7361 * @ctxt: the XPath Parser context
7362 *
7363 * parse an XML name
7364 *
7365 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7366 * CombiningChar | Extender
7367 *
7368 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7369 *
7370 * Returns the namespace name or NULL
7371 */
7372
7373xmlChar *
7374xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007375 const xmlChar *in;
7376 xmlChar *ret;
7377 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007378
Daniel Veillard61d80a22001-04-27 17:13:01 +00007379 /*
7380 * Accelerator for simple ASCII names
7381 */
7382 in = ctxt->cur;
7383 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7384 ((*in >= 0x41) && (*in <= 0x5A)) ||
7385 (*in == '_') || (*in == ':')) {
7386 in++;
7387 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7388 ((*in >= 0x41) && (*in <= 0x5A)) ||
7389 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007390 (*in == '_') || (*in == '-') ||
7391 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007392 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007393 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007394 count = in - ctxt->cur;
7395 ret = xmlStrndup(ctxt->cur, count);
7396 ctxt->cur = in;
7397 return(ret);
7398 }
7399 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007400 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007401}
7402
Daniel Veillard61d80a22001-04-27 17:13:01 +00007403static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007404xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007405 xmlChar buf[XML_MAX_NAMELEN + 5];
7406 int len = 0, l;
7407 int c;
7408
7409 /*
7410 * Handler for more complex cases
7411 */
7412 c = CUR_CHAR(l);
7413 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007414 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7415 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007416 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007417 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007418 return(NULL);
7419 }
7420
7421 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7422 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7423 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007424 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007425 (IS_COMBINING(c)) ||
7426 (IS_EXTENDER(c)))) {
7427 COPY_BUF(l,buf,len,c);
7428 NEXTL(l);
7429 c = CUR_CHAR(l);
7430 if (len >= XML_MAX_NAMELEN) {
7431 /*
7432 * Okay someone managed to make a huge name, so he's ready to pay
7433 * for the processing speed.
7434 */
7435 xmlChar *buffer;
7436 int max = len * 2;
7437
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007438 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007439 if (buffer == NULL) {
7440 XP_ERROR0(XPATH_MEMORY_ERROR);
7441 }
7442 memcpy(buffer, buf, len);
7443 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7444 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007445 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007446 (IS_COMBINING(c)) ||
7447 (IS_EXTENDER(c))) {
7448 if (len + 10 > max) {
7449 max *= 2;
7450 buffer = (xmlChar *) xmlRealloc(buffer,
7451 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007452 if (buffer == NULL) {
7453 XP_ERROR0(XPATH_MEMORY_ERROR);
7454 }
7455 }
7456 COPY_BUF(l,buffer,len,c);
7457 NEXTL(l);
7458 c = CUR_CHAR(l);
7459 }
7460 buffer[len] = 0;
7461 return(buffer);
7462 }
7463 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007464 if (len == 0)
7465 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007466 return(xmlStrndup(buf, len));
7467}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007468
7469#define MAX_FRAC 20
7470
7471static double my_pow10[MAX_FRAC] = {
7472 1.0, 10.0, 100.0, 1000.0, 10000.0,
7473 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7474 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7475 100000000000000.0,
7476 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7477 1000000000000000000.0, 10000000000000000000.0
7478};
7479
Owen Taylor3473f882001-02-23 17:55:21 +00007480/**
7481 * xmlXPathStringEvalNumber:
7482 * @str: A string to scan
7483 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007484 * [30a] Float ::= Number ('e' Digits?)?
7485 *
Owen Taylor3473f882001-02-23 17:55:21 +00007486 * [30] Number ::= Digits ('.' Digits?)?
7487 * | '.' Digits
7488 * [31] Digits ::= [0-9]+
7489 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007490 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007491 * In complement of the Number expression, this function also handles
7492 * negative values : '-' Number.
7493 *
7494 * Returns the double value.
7495 */
7496double
7497xmlXPathStringEvalNumber(const xmlChar *str) {
7498 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007499 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007500 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007501 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007502 int exponent = 0;
7503 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007504#ifdef __GNUC__
7505 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007506 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007507#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007508 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007509 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007510 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7511 return(xmlXPathNAN);
7512 }
7513 if (*cur == '-') {
7514 isneg = 1;
7515 cur++;
7516 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007517
7518#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007519 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007520 * tmp/temp is a workaround against a gcc compiler bug
7521 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007522 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007523 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007524 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007525 ret = ret * 10;
7526 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007527 ok = 1;
7528 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007529 temp = (double) tmp;
7530 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007531 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007532#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007533 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007534 while ((*cur >= '0') && (*cur <= '9')) {
7535 ret = ret * 10 + (*cur - '0');
7536 ok = 1;
7537 cur++;
7538 }
7539#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007540
Owen Taylor3473f882001-02-23 17:55:21 +00007541 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007542 int v, frac = 0;
7543 double fraction = 0;
7544
Owen Taylor3473f882001-02-23 17:55:21 +00007545 cur++;
7546 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7547 return(xmlXPathNAN);
7548 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007549 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7550 v = (*cur - '0');
7551 fraction = fraction * 10 + v;
7552 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007553 cur++;
7554 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007555 fraction /= my_pow10[frac];
7556 ret = ret + fraction;
7557 while ((*cur >= '0') && (*cur <= '9'))
7558 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007559 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007560 if ((*cur == 'e') || (*cur == 'E')) {
7561 cur++;
7562 if (*cur == '-') {
7563 is_exponent_negative = 1;
7564 cur++;
7565 }
7566 while ((*cur >= '0') && (*cur <= '9')) {
7567 exponent = exponent * 10 + (*cur - '0');
7568 cur++;
7569 }
7570 }
William M. Brack76e95df2003-10-18 16:20:14 +00007571 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007572 if (*cur != 0) return(xmlXPathNAN);
7573 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007574 if (is_exponent_negative) exponent = -exponent;
7575 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007576 return(ret);
7577}
7578
7579/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007580 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007581 * @ctxt: the XPath Parser context
7582 *
7583 * [30] Number ::= Digits ('.' Digits?)?
7584 * | '.' Digits
7585 * [31] Digits ::= [0-9]+
7586 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007587 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007588 *
7589 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007590static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007591xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7592{
Owen Taylor3473f882001-02-23 17:55:21 +00007593 double ret = 0.0;
7594 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007595 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007596 int exponent = 0;
7597 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007598#ifdef __GNUC__
7599 unsigned long tmp = 0;
7600 double temp;
7601#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007602
7603 CHECK_ERROR;
7604 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7605 XP_ERROR(XPATH_NUMBER_ERROR);
7606 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007607#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007608 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007609 * tmp/temp is a workaround against a gcc compiler bug
7610 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007611 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007612 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007613 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007614 ret = ret * 10;
7615 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007616 ok = 1;
7617 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007618 temp = (double) tmp;
7619 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007620 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007621#else
7622 ret = 0;
7623 while ((CUR >= '0') && (CUR <= '9')) {
7624 ret = ret * 10 + (CUR - '0');
7625 ok = 1;
7626 NEXT;
7627 }
7628#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007629 if (CUR == '.') {
7630 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007631 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7632 XP_ERROR(XPATH_NUMBER_ERROR);
7633 }
7634 while ((CUR >= '0') && (CUR <= '9')) {
7635 mult /= 10;
7636 ret = ret + (CUR - '0') * mult;
7637 NEXT;
7638 }
Owen Taylor3473f882001-02-23 17:55:21 +00007639 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007640 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007641 NEXT;
7642 if (CUR == '-') {
7643 is_exponent_negative = 1;
7644 NEXT;
7645 }
7646 while ((CUR >= '0') && (CUR <= '9')) {
7647 exponent = exponent * 10 + (CUR - '0');
7648 NEXT;
7649 }
7650 if (is_exponent_negative)
7651 exponent = -exponent;
7652 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007653 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007654 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007655 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007656}
7657
7658/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007659 * xmlXPathParseLiteral:
7660 * @ctxt: the XPath Parser context
7661 *
7662 * Parse a Literal
7663 *
7664 * [29] Literal ::= '"' [^"]* '"'
7665 * | "'" [^']* "'"
7666 *
7667 * Returns the value found or NULL in case of error
7668 */
7669static xmlChar *
7670xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7671 const xmlChar *q;
7672 xmlChar *ret = NULL;
7673
7674 if (CUR == '"') {
7675 NEXT;
7676 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007677 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007678 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007679 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007680 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7681 } else {
7682 ret = xmlStrndup(q, CUR_PTR - q);
7683 NEXT;
7684 }
7685 } else if (CUR == '\'') {
7686 NEXT;
7687 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007688 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007689 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007690 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007691 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7692 } else {
7693 ret = xmlStrndup(q, CUR_PTR - q);
7694 NEXT;
7695 }
7696 } else {
7697 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7698 }
7699 return(ret);
7700}
7701
7702/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007703 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007704 * @ctxt: the XPath Parser context
7705 *
7706 * Parse a Literal and push it on the stack.
7707 *
7708 * [29] Literal ::= '"' [^"]* '"'
7709 * | "'" [^']* "'"
7710 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007711 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007712 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007713static void
7714xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007715 const xmlChar *q;
7716 xmlChar *ret = NULL;
7717
7718 if (CUR == '"') {
7719 NEXT;
7720 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007721 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007722 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007723 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007724 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7725 } else {
7726 ret = xmlStrndup(q, CUR_PTR - q);
7727 NEXT;
7728 }
7729 } else if (CUR == '\'') {
7730 NEXT;
7731 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007732 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007733 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007734 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007735 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7736 } else {
7737 ret = xmlStrndup(q, CUR_PTR - q);
7738 NEXT;
7739 }
7740 } else {
7741 XP_ERROR(XPATH_START_LITERAL_ERROR);
7742 }
7743 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007744 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7745 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007746 xmlFree(ret);
7747}
7748
7749/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007750 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007751 * @ctxt: the XPath Parser context
7752 *
7753 * Parse a VariableReference, evaluate it and push it on the stack.
7754 *
7755 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00007756 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00007757 * of any of the types that are possible for the value of an expression,
7758 * and may also be of additional types not specified here.
7759 *
7760 * Early evaluation is possible since:
7761 * The variable bindings [...] used to evaluate a subexpression are
7762 * always the same as those used to evaluate the containing expression.
7763 *
7764 * [36] VariableReference ::= '$' QName
7765 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007766static void
7767xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007768 xmlChar *name;
7769 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007770
7771 SKIP_BLANKS;
7772 if (CUR != '$') {
7773 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7774 }
7775 NEXT;
7776 name = xmlXPathParseQName(ctxt, &prefix);
7777 if (name == NULL) {
7778 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7779 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007780 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007781 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7782 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007783 SKIP_BLANKS;
7784}
7785
7786/**
7787 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007788 * @name: a name string
7789 *
7790 * Is the name given a NodeType one.
7791 *
7792 * [38] NodeType ::= 'comment'
7793 * | 'text'
7794 * | 'processing-instruction'
7795 * | 'node'
7796 *
7797 * Returns 1 if true 0 otherwise
7798 */
7799int
7800xmlXPathIsNodeType(const xmlChar *name) {
7801 if (name == NULL)
7802 return(0);
7803
Daniel Veillard1971ee22002-01-31 20:29:19 +00007804 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007805 return(1);
7806 if (xmlStrEqual(name, BAD_CAST "text"))
7807 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007808 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007809 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007810 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007811 return(1);
7812 return(0);
7813}
7814
7815/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007816 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007817 * @ctxt: the XPath Parser context
7818 *
7819 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7820 * [17] Argument ::= Expr
7821 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007822 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007823 * pushed on the stack
7824 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007825static void
7826xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007827 xmlChar *name;
7828 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007829 int nbargs = 0;
7830
7831 name = xmlXPathParseQName(ctxt, &prefix);
7832 if (name == NULL) {
7833 XP_ERROR(XPATH_EXPR_ERROR);
7834 }
7835 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007836#ifdef DEBUG_EXPR
7837 if (prefix == NULL)
7838 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7839 name);
7840 else
7841 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7842 prefix, name);
7843#endif
7844
Owen Taylor3473f882001-02-23 17:55:21 +00007845 if (CUR != '(') {
7846 XP_ERROR(XPATH_EXPR_ERROR);
7847 }
7848 NEXT;
7849 SKIP_BLANKS;
7850
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007851 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007852 if (CUR != ')') {
7853 while (CUR != 0) {
7854 int op1 = ctxt->comp->last;
7855 ctxt->comp->last = -1;
7856 xmlXPathCompileExpr(ctxt);
7857 CHECK_ERROR;
7858 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7859 nbargs++;
7860 if (CUR == ')') break;
7861 if (CUR != ',') {
7862 XP_ERROR(XPATH_EXPR_ERROR);
7863 }
7864 NEXT;
7865 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007866 }
Owen Taylor3473f882001-02-23 17:55:21 +00007867 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007868 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7869 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007870 NEXT;
7871 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007872}
7873
7874/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007875 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007876 * @ctxt: the XPath Parser context
7877 *
7878 * [15] PrimaryExpr ::= VariableReference
7879 * | '(' Expr ')'
7880 * | Literal
7881 * | Number
7882 * | FunctionCall
7883 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007884 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007885 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007886static void
7887xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007888 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007889 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007890 else if (CUR == '(') {
7891 NEXT;
7892 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007893 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007894 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007895 if (CUR != ')') {
7896 XP_ERROR(XPATH_EXPR_ERROR);
7897 }
7898 NEXT;
7899 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007900 } else if (IS_DIGIT_CH(CUR) || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007901 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007902 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007903 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007904 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007905 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007906 }
7907 SKIP_BLANKS;
7908}
7909
7910/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007911 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007912 * @ctxt: the XPath Parser context
7913 *
7914 * [20] FilterExpr ::= PrimaryExpr
7915 * | FilterExpr Predicate
7916 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007917 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007918 * Square brackets are used to filter expressions in the same way that
7919 * they are used in location paths. It is an error if the expression to
7920 * be filtered does not evaluate to a node-set. The context node list
7921 * used for evaluating the expression in square brackets is the node-set
7922 * to be filtered listed in document order.
7923 */
7924
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007925static void
7926xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7927 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007928 CHECK_ERROR;
7929 SKIP_BLANKS;
7930
7931 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007932 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007933 SKIP_BLANKS;
7934 }
7935
7936
7937}
7938
7939/**
7940 * xmlXPathScanName:
7941 * @ctxt: the XPath Parser context
7942 *
7943 * Trickery: parse an XML name but without consuming the input flow
7944 * Needed to avoid insanity in the parser state.
7945 *
7946 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7947 * CombiningChar | Extender
7948 *
7949 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7950 *
7951 * [6] Names ::= Name (S Name)*
7952 *
7953 * Returns the Name parsed or NULL
7954 */
7955
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007956static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007957xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7958 xmlChar buf[XML_MAX_NAMELEN];
7959 int len = 0;
7960
7961 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007962 if (!IS_LETTER_CH(CUR) && (CUR != '_') &&
Owen Taylor3473f882001-02-23 17:55:21 +00007963 (CUR != ':')) {
7964 return(NULL);
7965 }
7966
William M. Brack76e95df2003-10-18 16:20:14 +00007967 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007968 (NXT(len) == '.') || (NXT(len) == '-') ||
7969 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00007970 (IS_COMBINING_CH(NXT(len))) ||
7971 (IS_EXTENDER_CH(NXT(len)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007972 buf[len] = NXT(len);
7973 len++;
7974 if (len >= XML_MAX_NAMELEN) {
7975 xmlGenericError(xmlGenericErrorContext,
7976 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
William M. Brack76e95df2003-10-18 16:20:14 +00007977 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007978 (NXT(len) == '.') || (NXT(len) == '-') ||
7979 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00007980 (IS_COMBINING_CH(NXT(len))) ||
7981 (IS_EXTENDER_CH(NXT(len))))
Owen Taylor3473f882001-02-23 17:55:21 +00007982 len++;
7983 break;
7984 }
7985 }
7986 return(xmlStrndup(buf, len));
7987}
7988
7989/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007990 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007991 * @ctxt: the XPath Parser context
7992 *
7993 * [19] PathExpr ::= LocationPath
7994 * | FilterExpr
7995 * | FilterExpr '/' RelativeLocationPath
7996 * | FilterExpr '//' RelativeLocationPath
7997 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007998 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007999 * The / operator and // operators combine an arbitrary expression
8000 * and a relative location path. It is an error if the expression
8001 * does not evaluate to a node-set.
8002 * The / operator does composition in the same way as when / is
8003 * used in a location path. As in location paths, // is short for
8004 * /descendant-or-self::node()/.
8005 */
8006
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008007static void
8008xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008009 int lc = 1; /* Should we branch to LocationPath ? */
8010 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8011
8012 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00008013 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT_CH(CUR)) ||
8014 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008015 lc = 0;
8016 } else if (CUR == '*') {
8017 /* relative or absolute location path */
8018 lc = 1;
8019 } else if (CUR == '/') {
8020 /* relative or absolute location path */
8021 lc = 1;
8022 } else if (CUR == '@') {
8023 /* relative abbreviated attribute location path */
8024 lc = 1;
8025 } else if (CUR == '.') {
8026 /* relative abbreviated attribute location path */
8027 lc = 1;
8028 } else {
8029 /*
8030 * Problem is finding if we have a name here whether it's:
8031 * - a nodetype
8032 * - a function call in which case it's followed by '('
8033 * - an axis in which case it's followed by ':'
8034 * - a element name
8035 * We do an a priori analysis here rather than having to
8036 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008037 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008038 * read/write/debug.
8039 */
8040 SKIP_BLANKS;
8041 name = xmlXPathScanName(ctxt);
8042 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8043#ifdef DEBUG_STEP
8044 xmlGenericError(xmlGenericErrorContext,
8045 "PathExpr: Axis\n");
8046#endif
8047 lc = 1;
8048 xmlFree(name);
8049 } else if (name != NULL) {
8050 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008051
8052
8053 while (NXT(len) != 0) {
8054 if (NXT(len) == '/') {
8055 /* element name */
8056#ifdef DEBUG_STEP
8057 xmlGenericError(xmlGenericErrorContext,
8058 "PathExpr: AbbrRelLocation\n");
8059#endif
8060 lc = 1;
8061 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008062 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008063 /* ignore blanks */
8064 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008065 } else if (NXT(len) == ':') {
8066#ifdef DEBUG_STEP
8067 xmlGenericError(xmlGenericErrorContext,
8068 "PathExpr: AbbrRelLocation\n");
8069#endif
8070 lc = 1;
8071 break;
8072 } else if ((NXT(len) == '(')) {
8073 /* Note Type or Function */
8074 if (xmlXPathIsNodeType(name)) {
8075#ifdef DEBUG_STEP
8076 xmlGenericError(xmlGenericErrorContext,
8077 "PathExpr: Type search\n");
8078#endif
8079 lc = 1;
8080 } else {
8081#ifdef DEBUG_STEP
8082 xmlGenericError(xmlGenericErrorContext,
8083 "PathExpr: function call\n");
8084#endif
8085 lc = 0;
8086 }
8087 break;
8088 } else if ((NXT(len) == '[')) {
8089 /* element name */
8090#ifdef DEBUG_STEP
8091 xmlGenericError(xmlGenericErrorContext,
8092 "PathExpr: AbbrRelLocation\n");
8093#endif
8094 lc = 1;
8095 break;
8096 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8097 (NXT(len) == '=')) {
8098 lc = 1;
8099 break;
8100 } else {
8101 lc = 1;
8102 break;
8103 }
8104 len++;
8105 }
8106 if (NXT(len) == 0) {
8107#ifdef DEBUG_STEP
8108 xmlGenericError(xmlGenericErrorContext,
8109 "PathExpr: AbbrRelLocation\n");
8110#endif
8111 /* element name */
8112 lc = 1;
8113 }
8114 xmlFree(name);
8115 } else {
William M. Brack08171912003-12-29 02:52:11 +00008116 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008117 XP_ERROR(XPATH_EXPR_ERROR);
8118 }
8119 }
8120
8121 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008122 if (CUR == '/') {
8123 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8124 } else {
8125 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008126 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008127 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008128 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008129 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008130 CHECK_ERROR;
8131 if ((CUR == '/') && (NXT(1) == '/')) {
8132 SKIP(2);
8133 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008134
8135 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8136 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8137 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8138
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008139 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008140 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008141 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008142 }
8143 }
8144 SKIP_BLANKS;
8145}
8146
8147/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008148 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008149 * @ctxt: the XPath Parser context
8150 *
8151 * [18] UnionExpr ::= PathExpr
8152 * | UnionExpr '|' PathExpr
8153 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008154 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008155 */
8156
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008157static void
8158xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8159 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008160 CHECK_ERROR;
8161 SKIP_BLANKS;
8162 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008163 int op1 = ctxt->comp->last;
8164 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008165
8166 NEXT;
8167 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008168 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008169
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008170 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8171
Owen Taylor3473f882001-02-23 17:55:21 +00008172 SKIP_BLANKS;
8173 }
Owen Taylor3473f882001-02-23 17:55:21 +00008174}
8175
8176/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008177 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008178 * @ctxt: the XPath Parser context
8179 *
8180 * [27] UnaryExpr ::= UnionExpr
8181 * | '-' UnaryExpr
8182 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008183 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008184 */
8185
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008186static void
8187xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008188 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008189 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008190
8191 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008192 while (CUR == '-') {
8193 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008194 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008195 NEXT;
8196 SKIP_BLANKS;
8197 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008198
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008199 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008200 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008201 if (found) {
8202 if (minus)
8203 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8204 else
8205 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008206 }
8207}
8208
8209/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008210 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008211 * @ctxt: the XPath Parser context
8212 *
8213 * [26] MultiplicativeExpr ::= UnaryExpr
8214 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8215 * | MultiplicativeExpr 'div' UnaryExpr
8216 * | MultiplicativeExpr 'mod' UnaryExpr
8217 * [34] MultiplyOperator ::= '*'
8218 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008219 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008220 */
8221
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008222static void
8223xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8224 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008225 CHECK_ERROR;
8226 SKIP_BLANKS;
8227 while ((CUR == '*') ||
8228 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8229 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8230 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008231 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008232
8233 if (CUR == '*') {
8234 op = 0;
8235 NEXT;
8236 } else if (CUR == 'd') {
8237 op = 1;
8238 SKIP(3);
8239 } else if (CUR == 'm') {
8240 op = 2;
8241 SKIP(3);
8242 }
8243 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008244 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008245 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008246 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008247 SKIP_BLANKS;
8248 }
8249}
8250
8251/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008252 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008253 * @ctxt: the XPath Parser context
8254 *
8255 * [25] AdditiveExpr ::= MultiplicativeExpr
8256 * | AdditiveExpr '+' MultiplicativeExpr
8257 * | AdditiveExpr '-' MultiplicativeExpr
8258 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008259 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008260 */
8261
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008262static void
8263xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008264
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008265 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008266 CHECK_ERROR;
8267 SKIP_BLANKS;
8268 while ((CUR == '+') || (CUR == '-')) {
8269 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008270 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008271
8272 if (CUR == '+') plus = 1;
8273 else plus = 0;
8274 NEXT;
8275 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008276 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008277 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008278 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008279 SKIP_BLANKS;
8280 }
8281}
8282
8283/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008284 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008285 * @ctxt: the XPath Parser context
8286 *
8287 * [24] RelationalExpr ::= AdditiveExpr
8288 * | RelationalExpr '<' AdditiveExpr
8289 * | RelationalExpr '>' AdditiveExpr
8290 * | RelationalExpr '<=' AdditiveExpr
8291 * | RelationalExpr '>=' AdditiveExpr
8292 *
8293 * A <= B > C is allowed ? Answer from James, yes with
8294 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8295 * which is basically what got implemented.
8296 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008297 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008298 * on the stack
8299 */
8300
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008301static void
8302xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8303 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008304 CHECK_ERROR;
8305 SKIP_BLANKS;
8306 while ((CUR == '<') ||
8307 (CUR == '>') ||
8308 ((CUR == '<') && (NXT(1) == '=')) ||
8309 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008310 int inf, strict;
8311 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008312
8313 if (CUR == '<') inf = 1;
8314 else inf = 0;
8315 if (NXT(1) == '=') strict = 0;
8316 else strict = 1;
8317 NEXT;
8318 if (!strict) NEXT;
8319 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008320 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008321 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008322 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008323 SKIP_BLANKS;
8324 }
8325}
8326
8327/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008328 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008329 * @ctxt: the XPath Parser context
8330 *
8331 * [23] EqualityExpr ::= RelationalExpr
8332 * | EqualityExpr '=' RelationalExpr
8333 * | EqualityExpr '!=' RelationalExpr
8334 *
8335 * A != B != C is allowed ? Answer from James, yes with
8336 * (RelationalExpr = RelationalExpr) = RelationalExpr
8337 * (RelationalExpr != RelationalExpr) != RelationalExpr
8338 * which is basically what got implemented.
8339 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008340 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008341 *
8342 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008343static void
8344xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8345 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008346 CHECK_ERROR;
8347 SKIP_BLANKS;
8348 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008349 int eq;
8350 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008351
8352 if (CUR == '=') eq = 1;
8353 else eq = 0;
8354 NEXT;
8355 if (!eq) NEXT;
8356 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008357 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008358 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008359 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008360 SKIP_BLANKS;
8361 }
8362}
8363
8364/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008365 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008366 * @ctxt: the XPath Parser context
8367 *
8368 * [22] AndExpr ::= EqualityExpr
8369 * | AndExpr 'and' EqualityExpr
8370 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008371 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008372 *
8373 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008374static void
8375xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8376 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008377 CHECK_ERROR;
8378 SKIP_BLANKS;
8379 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008380 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008381 SKIP(3);
8382 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008383 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008384 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008385 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008386 SKIP_BLANKS;
8387 }
8388}
8389
8390/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008391 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008392 * @ctxt: the XPath Parser context
8393 *
8394 * [14] Expr ::= OrExpr
8395 * [21] OrExpr ::= AndExpr
8396 * | OrExpr 'or' AndExpr
8397 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008398 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008399 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008400static void
8401xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8402 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008403 CHECK_ERROR;
8404 SKIP_BLANKS;
8405 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008406 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008407 SKIP(2);
8408 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008409 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008410 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008411 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8412 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008413 SKIP_BLANKS;
8414 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008415 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8416 /* more ops could be optimized too */
8417 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8418 }
Owen Taylor3473f882001-02-23 17:55:21 +00008419}
8420
8421/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008422 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008423 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008424 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008425 *
8426 * [8] Predicate ::= '[' PredicateExpr ']'
8427 * [9] PredicateExpr ::= Expr
8428 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008429 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008430 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008431static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008432xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008433 int op1 = ctxt->comp->last;
8434
8435 SKIP_BLANKS;
8436 if (CUR != '[') {
8437 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8438 }
8439 NEXT;
8440 SKIP_BLANKS;
8441
8442 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008443 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008444 CHECK_ERROR;
8445
8446 if (CUR != ']') {
8447 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8448 }
8449
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008450 if (filter)
8451 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8452 else
8453 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008454
8455 NEXT;
8456 SKIP_BLANKS;
8457}
8458
8459/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008460 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008461 * @ctxt: the XPath Parser context
8462 * @test: pointer to a xmlXPathTestVal
8463 * @type: pointer to a xmlXPathTypeVal
8464 * @prefix: placeholder for a possible name prefix
8465 *
8466 * [7] NodeTest ::= NameTest
8467 * | NodeType '(' ')'
8468 * | 'processing-instruction' '(' Literal ')'
8469 *
8470 * [37] NameTest ::= '*'
8471 * | NCName ':' '*'
8472 * | QName
8473 * [38] NodeType ::= 'comment'
8474 * | 'text'
8475 * | 'processing-instruction'
8476 * | 'node'
8477 *
William M. Brack08171912003-12-29 02:52:11 +00008478 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00008479 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008480static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008481xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8482 xmlXPathTypeVal *type, const xmlChar **prefix,
8483 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008484 int blanks;
8485
8486 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8487 STRANGE;
8488 return(NULL);
8489 }
William M. Brack78637da2003-07-31 14:47:38 +00008490 *type = (xmlXPathTypeVal) 0;
8491 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008492 *prefix = NULL;
8493 SKIP_BLANKS;
8494
8495 if ((name == NULL) && (CUR == '*')) {
8496 /*
8497 * All elements
8498 */
8499 NEXT;
8500 *test = NODE_TEST_ALL;
8501 return(NULL);
8502 }
8503
8504 if (name == NULL)
8505 name = xmlXPathParseNCName(ctxt);
8506 if (name == NULL) {
8507 XP_ERROR0(XPATH_EXPR_ERROR);
8508 }
8509
William M. Brack76e95df2003-10-18 16:20:14 +00008510 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008511 SKIP_BLANKS;
8512 if (CUR == '(') {
8513 NEXT;
8514 /*
8515 * NodeType or PI search
8516 */
8517 if (xmlStrEqual(name, BAD_CAST "comment"))
8518 *type = NODE_TYPE_COMMENT;
8519 else if (xmlStrEqual(name, BAD_CAST "node"))
8520 *type = NODE_TYPE_NODE;
8521 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8522 *type = NODE_TYPE_PI;
8523 else if (xmlStrEqual(name, BAD_CAST "text"))
8524 *type = NODE_TYPE_TEXT;
8525 else {
8526 if (name != NULL)
8527 xmlFree(name);
8528 XP_ERROR0(XPATH_EXPR_ERROR);
8529 }
8530
8531 *test = NODE_TEST_TYPE;
8532
8533 SKIP_BLANKS;
8534 if (*type == NODE_TYPE_PI) {
8535 /*
8536 * Specific case: search a PI by name.
8537 */
Owen Taylor3473f882001-02-23 17:55:21 +00008538 if (name != NULL)
8539 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008540 name = NULL;
8541 if (CUR != ')') {
8542 name = xmlXPathParseLiteral(ctxt);
8543 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008544 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008545 SKIP_BLANKS;
8546 }
Owen Taylor3473f882001-02-23 17:55:21 +00008547 }
8548 if (CUR != ')') {
8549 if (name != NULL)
8550 xmlFree(name);
8551 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8552 }
8553 NEXT;
8554 return(name);
8555 }
8556 *test = NODE_TEST_NAME;
8557 if ((!blanks) && (CUR == ':')) {
8558 NEXT;
8559
8560 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008561 * Since currently the parser context don't have a
8562 * namespace list associated:
8563 * The namespace name for this prefix can be computed
8564 * only at evaluation time. The compilation is done
8565 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008566 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008567#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008568 *prefix = xmlXPathNsLookup(ctxt->context, name);
8569 if (name != NULL)
8570 xmlFree(name);
8571 if (*prefix == NULL) {
8572 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8573 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008574#else
8575 *prefix = name;
8576#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008577
8578 if (CUR == '*') {
8579 /*
8580 * All elements
8581 */
8582 NEXT;
8583 *test = NODE_TEST_ALL;
8584 return(NULL);
8585 }
8586
8587 name = xmlXPathParseNCName(ctxt);
8588 if (name == NULL) {
8589 XP_ERROR0(XPATH_EXPR_ERROR);
8590 }
8591 }
8592 return(name);
8593}
8594
8595/**
8596 * xmlXPathIsAxisName:
8597 * @name: a preparsed name token
8598 *
8599 * [6] AxisName ::= 'ancestor'
8600 * | 'ancestor-or-self'
8601 * | 'attribute'
8602 * | 'child'
8603 * | 'descendant'
8604 * | 'descendant-or-self'
8605 * | 'following'
8606 * | 'following-sibling'
8607 * | 'namespace'
8608 * | 'parent'
8609 * | 'preceding'
8610 * | 'preceding-sibling'
8611 * | 'self'
8612 *
8613 * Returns the axis or 0
8614 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008615static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008616xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008617 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008618 switch (name[0]) {
8619 case 'a':
8620 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8621 ret = AXIS_ANCESTOR;
8622 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8623 ret = AXIS_ANCESTOR_OR_SELF;
8624 if (xmlStrEqual(name, BAD_CAST "attribute"))
8625 ret = AXIS_ATTRIBUTE;
8626 break;
8627 case 'c':
8628 if (xmlStrEqual(name, BAD_CAST "child"))
8629 ret = AXIS_CHILD;
8630 break;
8631 case 'd':
8632 if (xmlStrEqual(name, BAD_CAST "descendant"))
8633 ret = AXIS_DESCENDANT;
8634 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8635 ret = AXIS_DESCENDANT_OR_SELF;
8636 break;
8637 case 'f':
8638 if (xmlStrEqual(name, BAD_CAST "following"))
8639 ret = AXIS_FOLLOWING;
8640 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8641 ret = AXIS_FOLLOWING_SIBLING;
8642 break;
8643 case 'n':
8644 if (xmlStrEqual(name, BAD_CAST "namespace"))
8645 ret = AXIS_NAMESPACE;
8646 break;
8647 case 'p':
8648 if (xmlStrEqual(name, BAD_CAST "parent"))
8649 ret = AXIS_PARENT;
8650 if (xmlStrEqual(name, BAD_CAST "preceding"))
8651 ret = AXIS_PRECEDING;
8652 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8653 ret = AXIS_PRECEDING_SIBLING;
8654 break;
8655 case 's':
8656 if (xmlStrEqual(name, BAD_CAST "self"))
8657 ret = AXIS_SELF;
8658 break;
8659 }
8660 return(ret);
8661}
8662
8663/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008664 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008665 * @ctxt: the XPath Parser context
8666 *
8667 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8668 * | AbbreviatedStep
8669 *
8670 * [12] AbbreviatedStep ::= '.' | '..'
8671 *
8672 * [5] AxisSpecifier ::= AxisName '::'
8673 * | AbbreviatedAxisSpecifier
8674 *
8675 * [13] AbbreviatedAxisSpecifier ::= '@'?
8676 *
8677 * Modified for XPtr range support as:
8678 *
8679 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8680 * | AbbreviatedStep
8681 * | 'range-to' '(' Expr ')' Predicate*
8682 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008683 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008684 * A location step of . is short for self::node(). This is
8685 * particularly useful in conjunction with //. For example, the
8686 * location path .//para is short for
8687 * self::node()/descendant-or-self::node()/child::para
8688 * and so will select all para descendant elements of the context
8689 * node.
8690 * Similarly, a location step of .. is short for parent::node().
8691 * For example, ../title is short for parent::node()/child::title
8692 * and so will select the title children of the parent of the context
8693 * node.
8694 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008695static void
8696xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008697#ifdef LIBXML_XPTR_ENABLED
8698 int rangeto = 0;
8699 int op2 = -1;
8700#endif
8701
Owen Taylor3473f882001-02-23 17:55:21 +00008702 SKIP_BLANKS;
8703 if ((CUR == '.') && (NXT(1) == '.')) {
8704 SKIP(2);
8705 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008706 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8707 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008708 } else if (CUR == '.') {
8709 NEXT;
8710 SKIP_BLANKS;
8711 } else {
8712 xmlChar *name = NULL;
8713 const xmlChar *prefix = NULL;
8714 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008715 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008716 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008717 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008718
8719 /*
8720 * The modification needed for XPointer change to the production
8721 */
8722#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008723 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008724 name = xmlXPathParseNCName(ctxt);
8725 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008726 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008727 xmlFree(name);
8728 SKIP_BLANKS;
8729 if (CUR != '(') {
8730 XP_ERROR(XPATH_EXPR_ERROR);
8731 }
8732 NEXT;
8733 SKIP_BLANKS;
8734
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008735 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008736 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008737 CHECK_ERROR;
8738
8739 SKIP_BLANKS;
8740 if (CUR != ')') {
8741 XP_ERROR(XPATH_EXPR_ERROR);
8742 }
8743 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008744 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008745 goto eval_predicates;
8746 }
8747 }
8748#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008749 if (CUR == '*') {
8750 axis = AXIS_CHILD;
8751 } else {
8752 if (name == NULL)
8753 name = xmlXPathParseNCName(ctxt);
8754 if (name != NULL) {
8755 axis = xmlXPathIsAxisName(name);
8756 if (axis != 0) {
8757 SKIP_BLANKS;
8758 if ((CUR == ':') && (NXT(1) == ':')) {
8759 SKIP(2);
8760 xmlFree(name);
8761 name = NULL;
8762 } else {
8763 /* an element name can conflict with an axis one :-\ */
8764 axis = AXIS_CHILD;
8765 }
Owen Taylor3473f882001-02-23 17:55:21 +00008766 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008767 axis = AXIS_CHILD;
8768 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008769 } else if (CUR == '@') {
8770 NEXT;
8771 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008772 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008773 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008774 }
Owen Taylor3473f882001-02-23 17:55:21 +00008775 }
8776
8777 CHECK_ERROR;
8778
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008779 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008780 if (test == 0)
8781 return;
8782
8783#ifdef DEBUG_STEP
8784 xmlGenericError(xmlGenericErrorContext,
8785 "Basis : computing new set\n");
8786#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008787
Owen Taylor3473f882001-02-23 17:55:21 +00008788#ifdef DEBUG_STEP
8789 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008790 if (ctxt->value == NULL)
8791 xmlGenericError(xmlGenericErrorContext, "no value\n");
8792 else if (ctxt->value->nodesetval == NULL)
8793 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8794 else
8795 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008796#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008797
8798eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008799 op1 = ctxt->comp->last;
8800 ctxt->comp->last = -1;
8801
Owen Taylor3473f882001-02-23 17:55:21 +00008802 SKIP_BLANKS;
8803 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008804 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008805 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008806
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008807#ifdef LIBXML_XPTR_ENABLED
8808 if (rangeto) {
8809 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8810 } else
8811#endif
8812 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8813 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008814
Owen Taylor3473f882001-02-23 17:55:21 +00008815 }
8816#ifdef DEBUG_STEP
8817 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008818 if (ctxt->value == NULL)
8819 xmlGenericError(xmlGenericErrorContext, "no value\n");
8820 else if (ctxt->value->nodesetval == NULL)
8821 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8822 else
8823 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8824 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008825#endif
8826}
8827
8828/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008829 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008830 * @ctxt: the XPath Parser context
8831 *
8832 * [3] RelativeLocationPath ::= Step
8833 * | RelativeLocationPath '/' Step
8834 * | AbbreviatedRelativeLocationPath
8835 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8836 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008837 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008838 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008839static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008840xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008841(xmlXPathParserContextPtr ctxt) {
8842 SKIP_BLANKS;
8843 if ((CUR == '/') && (NXT(1) == '/')) {
8844 SKIP(2);
8845 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008846 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8847 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008848 } else if (CUR == '/') {
8849 NEXT;
8850 SKIP_BLANKS;
8851 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008852 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008853 SKIP_BLANKS;
8854 while (CUR == '/') {
8855 if ((CUR == '/') && (NXT(1) == '/')) {
8856 SKIP(2);
8857 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008858 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008859 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008860 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008861 } else if (CUR == '/') {
8862 NEXT;
8863 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008864 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008865 }
8866 SKIP_BLANKS;
8867 }
8868}
8869
8870/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008871 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008872 * @ctxt: the XPath Parser context
8873 *
8874 * [1] LocationPath ::= RelativeLocationPath
8875 * | AbsoluteLocationPath
8876 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8877 * | AbbreviatedAbsoluteLocationPath
8878 * [10] AbbreviatedAbsoluteLocationPath ::=
8879 * '//' RelativeLocationPath
8880 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008881 * Compile a location path
8882 *
Owen Taylor3473f882001-02-23 17:55:21 +00008883 * // is short for /descendant-or-self::node()/. For example,
8884 * //para is short for /descendant-or-self::node()/child::para and
8885 * so will select any para element in the document (even a para element
8886 * that is a document element will be selected by //para since the
8887 * document element node is a child of the root node); div//para is
8888 * short for div/descendant-or-self::node()/child::para and so will
8889 * select all para descendants of div children.
8890 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008891static void
8892xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008893 SKIP_BLANKS;
8894 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008895 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008896 } else {
8897 while (CUR == '/') {
8898 if ((CUR == '/') && (NXT(1) == '/')) {
8899 SKIP(2);
8900 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008901 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8902 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008903 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008904 } else if (CUR == '/') {
8905 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008906 SKIP_BLANKS;
8907 if ((CUR != 0 ) &&
William M. Brack76e95df2003-10-18 16:20:14 +00008908 ((IS_LETTER_CH(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00008909 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008910 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008911 }
8912 }
8913 }
8914}
8915
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008916/************************************************************************
8917 * *
8918 * XPath precompiled expression evaluation *
8919 * *
8920 ************************************************************************/
8921
Daniel Veillardf06307e2001-07-03 10:35:50 +00008922static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008923xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8924
8925/**
8926 * xmlXPathNodeCollectAndTest:
8927 * @ctxt: the XPath Parser context
8928 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008929 * @first: pointer to the first element in document order
8930 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008931 *
8932 * This is the function implementing a step: based on the current list
8933 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00008934 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008935 *
8936 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008937 *
William M. Brack08171912003-12-29 02:52:11 +00008938 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008939 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008940static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008941xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008942 xmlXPathStepOpPtr op,
8943 xmlNodePtr * first, xmlNodePtr * last)
8944{
William M. Brack78637da2003-07-31 14:47:38 +00008945 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
8946 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
8947 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008948 const xmlChar *prefix = op->value4;
8949 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008950 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008951
8952#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008953 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008954#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008955 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008956 xmlNodeSetPtr ret, list;
8957 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008958 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008959 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008960 xmlNodePtr cur = NULL;
8961 xmlXPathObjectPtr obj;
8962 xmlNodeSetPtr nodelist;
8963 xmlNodePtr tmp;
8964
Daniel Veillardf06307e2001-07-03 10:35:50 +00008965 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008966 obj = valuePop(ctxt);
8967 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008968 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008969 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008970 URI = xmlXPathNsLookup(ctxt->context, prefix);
8971 if (URI == NULL)
8972 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008973 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008974#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008975 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008976#endif
8977 switch (axis) {
8978 case AXIS_ANCESTOR:
8979#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008980 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008981#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008982 first = NULL;
8983 next = xmlXPathNextAncestor;
8984 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008985 case AXIS_ANCESTOR_OR_SELF:
8986#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008987 xmlGenericError(xmlGenericErrorContext,
8988 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008989#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008990 first = NULL;
8991 next = xmlXPathNextAncestorOrSelf;
8992 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008993 case AXIS_ATTRIBUTE:
8994#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008995 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008996#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008997 first = NULL;
8998 last = NULL;
8999 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009000 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009001 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009002 case AXIS_CHILD:
9003#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009004 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009005#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009006 last = NULL;
9007 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009008 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009009 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009010 case AXIS_DESCENDANT:
9011#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009012 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009013#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009014 last = NULL;
9015 next = xmlXPathNextDescendant;
9016 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009017 case AXIS_DESCENDANT_OR_SELF:
9018#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009019 xmlGenericError(xmlGenericErrorContext,
9020 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009021#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009022 last = NULL;
9023 next = xmlXPathNextDescendantOrSelf;
9024 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009025 case AXIS_FOLLOWING:
9026#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009027 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009028#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009029 last = NULL;
9030 next = xmlXPathNextFollowing;
9031 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009032 case AXIS_FOLLOWING_SIBLING:
9033#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009034 xmlGenericError(xmlGenericErrorContext,
9035 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009036#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009037 last = NULL;
9038 next = xmlXPathNextFollowingSibling;
9039 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009040 case AXIS_NAMESPACE:
9041#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009042 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009043#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009044 first = NULL;
9045 last = NULL;
9046 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009047 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009048 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009049 case AXIS_PARENT:
9050#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009051 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009052#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009053 first = NULL;
9054 next = xmlXPathNextParent;
9055 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009056 case AXIS_PRECEDING:
9057#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009058 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009059#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009060 first = NULL;
9061 next = xmlXPathNextPrecedingInternal;
9062 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009063 case AXIS_PRECEDING_SIBLING:
9064#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009065 xmlGenericError(xmlGenericErrorContext,
9066 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009067#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009068 first = NULL;
9069 next = xmlXPathNextPrecedingSibling;
9070 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009071 case AXIS_SELF:
9072#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009073 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009074#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009075 first = NULL;
9076 last = NULL;
9077 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009078 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009079 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009080 }
9081 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009082 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009083
9084 nodelist = obj->nodesetval;
9085 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009086 xmlXPathFreeObject(obj);
9087 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9088 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009089 }
9090 addNode = xmlXPathNodeSetAddUnique;
9091 ret = NULL;
9092#ifdef DEBUG_STEP
9093 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009094 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009095 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009096 case NODE_TEST_NONE:
9097 xmlGenericError(xmlGenericErrorContext,
9098 " searching for none !!!\n");
9099 break;
9100 case NODE_TEST_TYPE:
9101 xmlGenericError(xmlGenericErrorContext,
9102 " searching for type %d\n", type);
9103 break;
9104 case NODE_TEST_PI:
9105 xmlGenericError(xmlGenericErrorContext,
9106 " searching for PI !!!\n");
9107 break;
9108 case NODE_TEST_ALL:
9109 xmlGenericError(xmlGenericErrorContext,
9110 " searching for *\n");
9111 break;
9112 case NODE_TEST_NS:
9113 xmlGenericError(xmlGenericErrorContext,
9114 " searching for namespace %s\n",
9115 prefix);
9116 break;
9117 case NODE_TEST_NAME:
9118 xmlGenericError(xmlGenericErrorContext,
9119 " searching for name %s\n", name);
9120 if (prefix != NULL)
9121 xmlGenericError(xmlGenericErrorContext,
9122 " with namespace %s\n", prefix);
9123 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009124 }
9125 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9126#endif
9127 /*
9128 * 2.3 Node Tests
9129 * - For the attribute axis, the principal node type is attribute.
9130 * - For the namespace axis, the principal node type is namespace.
9131 * - For other axes, the principal node type is element.
9132 *
9133 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009134 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009135 * select all element children of the context node
9136 */
9137 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009138 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009139 ctxt->context->node = nodelist->nodeTab[i];
9140
Daniel Veillardf06307e2001-07-03 10:35:50 +00009141 cur = NULL;
9142 list = xmlXPathNodeSetCreate(NULL);
9143 do {
9144 cur = next(ctxt, cur);
9145 if (cur == NULL)
9146 break;
9147 if ((first != NULL) && (*first == cur))
9148 break;
9149 if (((t % 256) == 0) &&
9150 (first != NULL) && (*first != NULL) &&
9151 (xmlXPathCmpNodes(*first, cur) >= 0))
9152 break;
9153 if ((last != NULL) && (*last == cur))
9154 break;
9155 if (((t % 256) == 0) &&
9156 (last != NULL) && (*last != NULL) &&
9157 (xmlXPathCmpNodes(cur, *last) >= 0))
9158 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009159 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009160#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009161 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9162#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009163 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009164 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009165 ctxt->context->node = tmp;
9166 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009167 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009168 if ((cur->type == type) ||
9169 ((type == NODE_TYPE_NODE) &&
9170 ((cur->type == XML_DOCUMENT_NODE) ||
9171 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9172 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009173 (cur->type == XML_NAMESPACE_DECL) ||
9174 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009175 (cur->type == XML_PI_NODE) ||
9176 (cur->type == XML_COMMENT_NODE) ||
9177 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009178 (cur->type == XML_TEXT_NODE))) ||
9179 ((type == NODE_TYPE_TEXT) &&
9180 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009181#ifdef DEBUG_STEP
9182 n++;
9183#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009184 addNode(list, cur);
9185 }
9186 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009187 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009188 if (cur->type == XML_PI_NODE) {
9189 if ((name != NULL) &&
9190 (!xmlStrEqual(name, cur->name)))
9191 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009192#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009193 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009194#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009195 addNode(list, cur);
9196 }
9197 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009198 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009199 if (axis == AXIS_ATTRIBUTE) {
9200 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009201#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009202 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009203#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009204 addNode(list, cur);
9205 }
9206 } else if (axis == AXIS_NAMESPACE) {
9207 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009208#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009209 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009210#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009211 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9212 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009213 }
9214 } else {
9215 if (cur->type == XML_ELEMENT_NODE) {
9216 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009217#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009218 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009219#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009220 addNode(list, cur);
9221 } else if ((cur->ns != NULL) &&
9222 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009223#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009224 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009225#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009226 addNode(list, cur);
9227 }
9228 }
9229 }
9230 break;
9231 case NODE_TEST_NS:{
9232 TODO;
9233 break;
9234 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009235 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009236 switch (cur->type) {
9237 case XML_ELEMENT_NODE:
9238 if (xmlStrEqual(name, cur->name)) {
9239 if (prefix == NULL) {
9240 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009241#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009242 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009243#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009244 addNode(list, cur);
9245 }
9246 } else {
9247 if ((cur->ns != NULL) &&
9248 (xmlStrEqual(URI,
9249 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009250#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009251 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009252#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009253 addNode(list, cur);
9254 }
9255 }
9256 }
9257 break;
9258 case XML_ATTRIBUTE_NODE:{
9259 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009260
Daniel Veillardf06307e2001-07-03 10:35:50 +00009261 if (xmlStrEqual(name, attr->name)) {
9262 if (prefix == NULL) {
9263 if ((attr->ns == NULL) ||
9264 (attr->ns->prefix == NULL)) {
9265#ifdef DEBUG_STEP
9266 n++;
9267#endif
9268 addNode(list,
9269 (xmlNodePtr) attr);
9270 }
9271 } else {
9272 if ((attr->ns != NULL) &&
9273 (xmlStrEqual(URI,
9274 attr->ns->
9275 href))) {
9276#ifdef DEBUG_STEP
9277 n++;
9278#endif
9279 addNode(list,
9280 (xmlNodePtr) attr);
9281 }
9282 }
9283 }
9284 break;
9285 }
9286 case XML_NAMESPACE_DECL:
9287 if (cur->type == XML_NAMESPACE_DECL) {
9288 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009289
Daniel Veillardf06307e2001-07-03 10:35:50 +00009290 if ((ns->prefix != NULL) && (name != NULL)
9291 && (xmlStrEqual(ns->prefix, name))) {
9292#ifdef DEBUG_STEP
9293 n++;
9294#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009295 xmlXPathNodeSetAddNs(list,
9296 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009297 }
9298 }
9299 break;
9300 default:
9301 break;
9302 }
9303 break;
9304 break;
9305 }
9306 } while (cur != NULL);
9307
9308 /*
9309 * If there is some predicate filtering do it now
9310 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009311 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009312 xmlXPathObjectPtr obj2;
9313
9314 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9315 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9316 CHECK_TYPE0(XPATH_NODESET);
9317 obj2 = valuePop(ctxt);
9318 list = obj2->nodesetval;
9319 obj2->nodesetval = NULL;
9320 xmlXPathFreeObject(obj2);
9321 }
9322 if (ret == NULL) {
9323 ret = list;
9324 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009325 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009326 xmlXPathFreeNodeSet(list);
9327 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009328 }
9329 ctxt->context->node = tmp;
9330#ifdef DEBUG_STEP
9331 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009332 "\nExamined %d nodes, found %d nodes at that step\n",
9333 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009334#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009335 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009336 if ((obj->boolval) && (obj->user != NULL)) {
9337 ctxt->value->boolval = 1;
9338 ctxt->value->user = obj->user;
9339 obj->user = NULL;
9340 obj->boolval = 0;
9341 }
9342 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009343 return(t);
9344}
9345
9346/**
9347 * xmlXPathNodeCollectAndTestNth:
9348 * @ctxt: the XPath Parser context
9349 * @op: the XPath precompiled step operation
9350 * @indx: the index to collect
9351 * @first: pointer to the first element in document order
9352 * @last: pointer to the last element in document order
9353 *
9354 * This is the function implementing a step: based on the current list
9355 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009356 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009357 *
9358 * Pushes the new NodeSet resulting from the search.
9359 * Returns the number of node traversed
9360 */
9361static int
9362xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9363 xmlXPathStepOpPtr op, int indx,
9364 xmlNodePtr * first, xmlNodePtr * last)
9365{
William M. Brack78637da2003-07-31 14:47:38 +00009366 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9367 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9368 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009369 const xmlChar *prefix = op->value4;
9370 const xmlChar *name = op->value5;
9371 const xmlChar *URI = NULL;
9372 int n = 0, t = 0;
9373
9374 int i;
9375 xmlNodeSetPtr list;
9376 xmlXPathTraversalFunction next = NULL;
9377 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9378 xmlNodePtr cur = NULL;
9379 xmlXPathObjectPtr obj;
9380 xmlNodeSetPtr nodelist;
9381 xmlNodePtr tmp;
9382
9383 CHECK_TYPE0(XPATH_NODESET);
9384 obj = valuePop(ctxt);
9385 addNode = xmlXPathNodeSetAdd;
9386 if (prefix != NULL) {
9387 URI = xmlXPathNsLookup(ctxt->context, prefix);
9388 if (URI == NULL)
9389 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9390 }
9391#ifdef DEBUG_STEP_NTH
9392 xmlGenericError(xmlGenericErrorContext, "new step : ");
9393 if (first != NULL) {
9394 if (*first != NULL)
9395 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9396 (*first)->name);
9397 else
9398 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9399 }
9400 if (last != NULL) {
9401 if (*last != NULL)
9402 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9403 (*last)->name);
9404 else
9405 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9406 }
9407#endif
9408 switch (axis) {
9409 case AXIS_ANCESTOR:
9410#ifdef DEBUG_STEP_NTH
9411 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9412#endif
9413 first = NULL;
9414 next = xmlXPathNextAncestor;
9415 break;
9416 case AXIS_ANCESTOR_OR_SELF:
9417#ifdef DEBUG_STEP_NTH
9418 xmlGenericError(xmlGenericErrorContext,
9419 "axis 'ancestors-or-self' ");
9420#endif
9421 first = NULL;
9422 next = xmlXPathNextAncestorOrSelf;
9423 break;
9424 case AXIS_ATTRIBUTE:
9425#ifdef DEBUG_STEP_NTH
9426 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9427#endif
9428 first = NULL;
9429 last = NULL;
9430 next = xmlXPathNextAttribute;
9431 break;
9432 case AXIS_CHILD:
9433#ifdef DEBUG_STEP_NTH
9434 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9435#endif
9436 last = NULL;
9437 next = xmlXPathNextChild;
9438 break;
9439 case AXIS_DESCENDANT:
9440#ifdef DEBUG_STEP_NTH
9441 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9442#endif
9443 last = NULL;
9444 next = xmlXPathNextDescendant;
9445 break;
9446 case AXIS_DESCENDANT_OR_SELF:
9447#ifdef DEBUG_STEP_NTH
9448 xmlGenericError(xmlGenericErrorContext,
9449 "axis 'descendant-or-self' ");
9450#endif
9451 last = NULL;
9452 next = xmlXPathNextDescendantOrSelf;
9453 break;
9454 case AXIS_FOLLOWING:
9455#ifdef DEBUG_STEP_NTH
9456 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9457#endif
9458 last = NULL;
9459 next = xmlXPathNextFollowing;
9460 break;
9461 case AXIS_FOLLOWING_SIBLING:
9462#ifdef DEBUG_STEP_NTH
9463 xmlGenericError(xmlGenericErrorContext,
9464 "axis 'following-siblings' ");
9465#endif
9466 last = NULL;
9467 next = xmlXPathNextFollowingSibling;
9468 break;
9469 case AXIS_NAMESPACE:
9470#ifdef DEBUG_STEP_NTH
9471 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9472#endif
9473 last = NULL;
9474 first = NULL;
9475 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9476 break;
9477 case AXIS_PARENT:
9478#ifdef DEBUG_STEP_NTH
9479 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9480#endif
9481 first = NULL;
9482 next = xmlXPathNextParent;
9483 break;
9484 case AXIS_PRECEDING:
9485#ifdef DEBUG_STEP_NTH
9486 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9487#endif
9488 first = NULL;
9489 next = xmlXPathNextPrecedingInternal;
9490 break;
9491 case AXIS_PRECEDING_SIBLING:
9492#ifdef DEBUG_STEP_NTH
9493 xmlGenericError(xmlGenericErrorContext,
9494 "axis 'preceding-sibling' ");
9495#endif
9496 first = NULL;
9497 next = xmlXPathNextPrecedingSibling;
9498 break;
9499 case AXIS_SELF:
9500#ifdef DEBUG_STEP_NTH
9501 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9502#endif
9503 first = NULL;
9504 last = NULL;
9505 next = xmlXPathNextSelf;
9506 break;
9507 }
9508 if (next == NULL)
9509 return(0);
9510
9511 nodelist = obj->nodesetval;
9512 if (nodelist == NULL) {
9513 xmlXPathFreeObject(obj);
9514 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9515 return(0);
9516 }
9517 addNode = xmlXPathNodeSetAddUnique;
9518#ifdef DEBUG_STEP_NTH
9519 xmlGenericError(xmlGenericErrorContext,
9520 " context contains %d nodes\n", nodelist->nodeNr);
9521 switch (test) {
9522 case NODE_TEST_NONE:
9523 xmlGenericError(xmlGenericErrorContext,
9524 " searching for none !!!\n");
9525 break;
9526 case NODE_TEST_TYPE:
9527 xmlGenericError(xmlGenericErrorContext,
9528 " searching for type %d\n", type);
9529 break;
9530 case NODE_TEST_PI:
9531 xmlGenericError(xmlGenericErrorContext,
9532 " searching for PI !!!\n");
9533 break;
9534 case NODE_TEST_ALL:
9535 xmlGenericError(xmlGenericErrorContext,
9536 " searching for *\n");
9537 break;
9538 case NODE_TEST_NS:
9539 xmlGenericError(xmlGenericErrorContext,
9540 " searching for namespace %s\n",
9541 prefix);
9542 break;
9543 case NODE_TEST_NAME:
9544 xmlGenericError(xmlGenericErrorContext,
9545 " searching for name %s\n", name);
9546 if (prefix != NULL)
9547 xmlGenericError(xmlGenericErrorContext,
9548 " with namespace %s\n", prefix);
9549 break;
9550 }
9551 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9552#endif
9553 /*
9554 * 2.3 Node Tests
9555 * - For the attribute axis, the principal node type is attribute.
9556 * - For the namespace axis, the principal node type is namespace.
9557 * - For other axes, the principal node type is element.
9558 *
9559 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009560 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009561 * select all element children of the context node
9562 */
9563 tmp = ctxt->context->node;
9564 list = xmlXPathNodeSetCreate(NULL);
9565 for (i = 0; i < nodelist->nodeNr; i++) {
9566 ctxt->context->node = nodelist->nodeTab[i];
9567
9568 cur = NULL;
9569 n = 0;
9570 do {
9571 cur = next(ctxt, cur);
9572 if (cur == NULL)
9573 break;
9574 if ((first != NULL) && (*first == cur))
9575 break;
9576 if (((t % 256) == 0) &&
9577 (first != NULL) && (*first != NULL) &&
9578 (xmlXPathCmpNodes(*first, cur) >= 0))
9579 break;
9580 if ((last != NULL) && (*last == cur))
9581 break;
9582 if (((t % 256) == 0) &&
9583 (last != NULL) && (*last != NULL) &&
9584 (xmlXPathCmpNodes(cur, *last) >= 0))
9585 break;
9586 t++;
9587 switch (test) {
9588 case NODE_TEST_NONE:
9589 ctxt->context->node = tmp;
9590 STRANGE return(0);
9591 case NODE_TEST_TYPE:
9592 if ((cur->type == type) ||
9593 ((type == NODE_TYPE_NODE) &&
9594 ((cur->type == XML_DOCUMENT_NODE) ||
9595 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9596 (cur->type == XML_ELEMENT_NODE) ||
9597 (cur->type == XML_PI_NODE) ||
9598 (cur->type == XML_COMMENT_NODE) ||
9599 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009600 (cur->type == XML_TEXT_NODE))) ||
9601 ((type == NODE_TYPE_TEXT) &&
9602 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009603 n++;
9604 if (n == indx)
9605 addNode(list, cur);
9606 }
9607 break;
9608 case NODE_TEST_PI:
9609 if (cur->type == XML_PI_NODE) {
9610 if ((name != NULL) &&
9611 (!xmlStrEqual(name, cur->name)))
9612 break;
9613 n++;
9614 if (n == indx)
9615 addNode(list, cur);
9616 }
9617 break;
9618 case NODE_TEST_ALL:
9619 if (axis == AXIS_ATTRIBUTE) {
9620 if (cur->type == XML_ATTRIBUTE_NODE) {
9621 n++;
9622 if (n == indx)
9623 addNode(list, cur);
9624 }
9625 } else if (axis == AXIS_NAMESPACE) {
9626 if (cur->type == XML_NAMESPACE_DECL) {
9627 n++;
9628 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009629 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9630 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009631 }
9632 } else {
9633 if (cur->type == XML_ELEMENT_NODE) {
9634 if (prefix == NULL) {
9635 n++;
9636 if (n == indx)
9637 addNode(list, cur);
9638 } else if ((cur->ns != NULL) &&
9639 (xmlStrEqual(URI, cur->ns->href))) {
9640 n++;
9641 if (n == indx)
9642 addNode(list, cur);
9643 }
9644 }
9645 }
9646 break;
9647 case NODE_TEST_NS:{
9648 TODO;
9649 break;
9650 }
9651 case NODE_TEST_NAME:
9652 switch (cur->type) {
9653 case XML_ELEMENT_NODE:
9654 if (xmlStrEqual(name, cur->name)) {
9655 if (prefix == NULL) {
9656 if (cur->ns == NULL) {
9657 n++;
9658 if (n == indx)
9659 addNode(list, cur);
9660 }
9661 } else {
9662 if ((cur->ns != NULL) &&
9663 (xmlStrEqual(URI,
9664 cur->ns->href))) {
9665 n++;
9666 if (n == indx)
9667 addNode(list, cur);
9668 }
9669 }
9670 }
9671 break;
9672 case XML_ATTRIBUTE_NODE:{
9673 xmlAttrPtr attr = (xmlAttrPtr) cur;
9674
9675 if (xmlStrEqual(name, attr->name)) {
9676 if (prefix == NULL) {
9677 if ((attr->ns == NULL) ||
9678 (attr->ns->prefix == NULL)) {
9679 n++;
9680 if (n == indx)
9681 addNode(list, cur);
9682 }
9683 } else {
9684 if ((attr->ns != NULL) &&
9685 (xmlStrEqual(URI,
9686 attr->ns->
9687 href))) {
9688 n++;
9689 if (n == indx)
9690 addNode(list, cur);
9691 }
9692 }
9693 }
9694 break;
9695 }
9696 case XML_NAMESPACE_DECL:
9697 if (cur->type == XML_NAMESPACE_DECL) {
9698 xmlNsPtr ns = (xmlNsPtr) cur;
9699
9700 if ((ns->prefix != NULL) && (name != NULL)
9701 && (xmlStrEqual(ns->prefix, name))) {
9702 n++;
9703 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009704 xmlXPathNodeSetAddNs(list,
9705 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009706 }
9707 }
9708 break;
9709 default:
9710 break;
9711 }
9712 break;
9713 break;
9714 }
9715 } while (n < indx);
9716 }
9717 ctxt->context->node = tmp;
9718#ifdef DEBUG_STEP_NTH
9719 xmlGenericError(xmlGenericErrorContext,
9720 "\nExamined %d nodes, found %d nodes at that step\n",
9721 t, list->nodeNr);
9722#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009723 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009724 if ((obj->boolval) && (obj->user != NULL)) {
9725 ctxt->value->boolval = 1;
9726 ctxt->value->user = obj->user;
9727 obj->user = NULL;
9728 obj->boolval = 0;
9729 }
9730 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009731 return(t);
9732}
9733
9734/**
9735 * xmlXPathCompOpEvalFirst:
9736 * @ctxt: the XPath parser context with the compiled expression
9737 * @op: an XPath compiled operation
9738 * @first: the first elem found so far
9739 *
9740 * Evaluate the Precompiled XPath operation searching only the first
9741 * element in document order
9742 *
9743 * Returns the number of examined objects.
9744 */
9745static int
9746xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9747 xmlXPathStepOpPtr op, xmlNodePtr * first)
9748{
9749 int total = 0, cur;
9750 xmlXPathCompExprPtr comp;
9751 xmlXPathObjectPtr arg1, arg2;
9752
Daniel Veillard556c6682001-10-06 09:59:51 +00009753 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009754 comp = ctxt->comp;
9755 switch (op->op) {
9756 case XPATH_OP_END:
9757 return (0);
9758 case XPATH_OP_UNION:
9759 total =
9760 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9761 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009762 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009763 if ((ctxt->value != NULL)
9764 && (ctxt->value->type == XPATH_NODESET)
9765 && (ctxt->value->nodesetval != NULL)
9766 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9767 /*
9768 * limit tree traversing to first node in the result
9769 */
9770 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9771 *first = ctxt->value->nodesetval->nodeTab[0];
9772 }
9773 cur =
9774 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9775 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009776 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009777 CHECK_TYPE0(XPATH_NODESET);
9778 arg2 = valuePop(ctxt);
9779
9780 CHECK_TYPE0(XPATH_NODESET);
9781 arg1 = valuePop(ctxt);
9782
9783 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9784 arg2->nodesetval);
9785 valuePush(ctxt, arg1);
9786 xmlXPathFreeObject(arg2);
9787 /* optimizer */
9788 if (total > cur)
9789 xmlXPathCompSwap(op);
9790 return (total + cur);
9791 case XPATH_OP_ROOT:
9792 xmlXPathRoot(ctxt);
9793 return (0);
9794 case XPATH_OP_NODE:
9795 if (op->ch1 != -1)
9796 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009797 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009798 if (op->ch2 != -1)
9799 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009800 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009801 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9802 return (total);
9803 case XPATH_OP_RESET:
9804 if (op->ch1 != -1)
9805 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009806 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009807 if (op->ch2 != -1)
9808 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009809 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009810 ctxt->context->node = NULL;
9811 return (total);
9812 case XPATH_OP_COLLECT:{
9813 if (op->ch1 == -1)
9814 return (total);
9815
9816 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009817 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009818
9819 /*
9820 * Optimization for [n] selection where n is a number
9821 */
9822 if ((op->ch2 != -1) &&
9823 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9824 (comp->steps[op->ch2].ch1 == -1) &&
9825 (comp->steps[op->ch2].ch2 != -1) &&
9826 (comp->steps[comp->steps[op->ch2].ch2].op ==
9827 XPATH_OP_VALUE)) {
9828 xmlXPathObjectPtr val;
9829
9830 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9831 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9832 int indx = (int) val->floatval;
9833
9834 if (val->floatval == (float) indx) {
9835 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9836 first, NULL);
9837 return (total);
9838 }
9839 }
9840 }
9841 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9842 return (total);
9843 }
9844 case XPATH_OP_VALUE:
9845 valuePush(ctxt,
9846 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9847 return (0);
9848 case XPATH_OP_SORT:
9849 if (op->ch1 != -1)
9850 total +=
9851 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9852 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009853 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009854 if ((ctxt->value != NULL)
9855 && (ctxt->value->type == XPATH_NODESET)
9856 && (ctxt->value->nodesetval != NULL))
9857 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9858 return (total);
9859 default:
9860 return (xmlXPathCompOpEval(ctxt, op));
9861 }
9862}
9863
9864/**
9865 * xmlXPathCompOpEvalLast:
9866 * @ctxt: the XPath parser context with the compiled expression
9867 * @op: an XPath compiled operation
9868 * @last: the last elem found so far
9869 *
9870 * Evaluate the Precompiled XPath operation searching only the last
9871 * element in document order
9872 *
William M. Brack08171912003-12-29 02:52:11 +00009873 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +00009874 */
9875static int
9876xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9877 xmlNodePtr * last)
9878{
9879 int total = 0, cur;
9880 xmlXPathCompExprPtr comp;
9881 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +00009882 xmlNodePtr bak;
9883 xmlDocPtr bakd;
9884 int pp;
9885 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009886
Daniel Veillard556c6682001-10-06 09:59:51 +00009887 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009888 comp = ctxt->comp;
9889 switch (op->op) {
9890 case XPATH_OP_END:
9891 return (0);
9892 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +00009893 bakd = ctxt->context->doc;
9894 bak = ctxt->context->node;
9895 pp = ctxt->context->proximityPosition;
9896 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009897 total =
9898 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009899 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009900 if ((ctxt->value != NULL)
9901 && (ctxt->value->type == XPATH_NODESET)
9902 && (ctxt->value->nodesetval != NULL)
9903 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9904 /*
9905 * limit tree traversing to first node in the result
9906 */
9907 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9908 *last =
9909 ctxt->value->nodesetval->nodeTab[ctxt->value->
9910 nodesetval->nodeNr -
9911 1];
9912 }
William M. Brackce4fc562004-01-22 02:47:18 +00009913 ctxt->context->doc = bakd;
9914 ctxt->context->node = bak;
9915 ctxt->context->proximityPosition = pp;
9916 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009917 cur =
9918 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009919 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009920 if ((ctxt->value != NULL)
9921 && (ctxt->value->type == XPATH_NODESET)
9922 && (ctxt->value->nodesetval != NULL)
9923 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9924 }
9925 CHECK_TYPE0(XPATH_NODESET);
9926 arg2 = valuePop(ctxt);
9927
9928 CHECK_TYPE0(XPATH_NODESET);
9929 arg1 = valuePop(ctxt);
9930
9931 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9932 arg2->nodesetval);
9933 valuePush(ctxt, arg1);
9934 xmlXPathFreeObject(arg2);
9935 /* optimizer */
9936 if (total > cur)
9937 xmlXPathCompSwap(op);
9938 return (total + cur);
9939 case XPATH_OP_ROOT:
9940 xmlXPathRoot(ctxt);
9941 return (0);
9942 case XPATH_OP_NODE:
9943 if (op->ch1 != -1)
9944 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009945 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009946 if (op->ch2 != -1)
9947 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009948 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009949 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9950 return (total);
9951 case XPATH_OP_RESET:
9952 if (op->ch1 != -1)
9953 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009954 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009955 if (op->ch2 != -1)
9956 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009957 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009958 ctxt->context->node = NULL;
9959 return (total);
9960 case XPATH_OP_COLLECT:{
9961 if (op->ch1 == -1)
9962 return (0);
9963
9964 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009965 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009966
9967 /*
9968 * Optimization for [n] selection where n is a number
9969 */
9970 if ((op->ch2 != -1) &&
9971 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9972 (comp->steps[op->ch2].ch1 == -1) &&
9973 (comp->steps[op->ch2].ch2 != -1) &&
9974 (comp->steps[comp->steps[op->ch2].ch2].op ==
9975 XPATH_OP_VALUE)) {
9976 xmlXPathObjectPtr val;
9977
9978 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9979 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9980 int indx = (int) val->floatval;
9981
9982 if (val->floatval == (float) indx) {
9983 total +=
9984 xmlXPathNodeCollectAndTestNth(ctxt, op,
9985 indx, NULL,
9986 last);
9987 return (total);
9988 }
9989 }
9990 }
9991 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9992 return (total);
9993 }
9994 case XPATH_OP_VALUE:
9995 valuePush(ctxt,
9996 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9997 return (0);
9998 case XPATH_OP_SORT:
9999 if (op->ch1 != -1)
10000 total +=
10001 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10002 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010003 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010004 if ((ctxt->value != NULL)
10005 && (ctxt->value->type == XPATH_NODESET)
10006 && (ctxt->value->nodesetval != NULL))
10007 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10008 return (total);
10009 default:
10010 return (xmlXPathCompOpEval(ctxt, op));
10011 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010012}
10013
Owen Taylor3473f882001-02-23 17:55:21 +000010014/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010015 * xmlXPathCompOpEval:
10016 * @ctxt: the XPath parser context with the compiled expression
10017 * @op: an XPath compiled operation
10018 *
10019 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010020 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010021 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010022static int
10023xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10024{
10025 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010026 int equal, ret;
10027 xmlXPathCompExprPtr comp;
10028 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010029 xmlNodePtr bak;
10030 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010031 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010032 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010033
Daniel Veillard556c6682001-10-06 09:59:51 +000010034 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010035 comp = ctxt->comp;
10036 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010037 case XPATH_OP_END:
10038 return (0);
10039 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010040 bakd = ctxt->context->doc;
10041 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010042 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010043 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010044 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010045 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010046 xmlXPathBooleanFunction(ctxt, 1);
10047 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10048 return (total);
10049 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010050 ctxt->context->doc = bakd;
10051 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010052 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010053 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010054 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010055 if (ctxt->error) {
10056 xmlXPathFreeObject(arg2);
10057 return(0);
10058 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010059 xmlXPathBooleanFunction(ctxt, 1);
10060 arg1 = valuePop(ctxt);
10061 arg1->boolval &= arg2->boolval;
10062 valuePush(ctxt, arg1);
10063 xmlXPathFreeObject(arg2);
10064 return (total);
10065 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010066 bakd = ctxt->context->doc;
10067 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010068 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010069 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010070 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010071 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010072 xmlXPathBooleanFunction(ctxt, 1);
10073 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10074 return (total);
10075 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010076 ctxt->context->doc = bakd;
10077 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010078 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010079 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010080 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010081 if (ctxt->error) {
10082 xmlXPathFreeObject(arg2);
10083 return(0);
10084 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010085 xmlXPathBooleanFunction(ctxt, 1);
10086 arg1 = valuePop(ctxt);
10087 arg1->boolval |= arg2->boolval;
10088 valuePush(ctxt, arg1);
10089 xmlXPathFreeObject(arg2);
10090 return (total);
10091 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010092 bakd = ctxt->context->doc;
10093 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010094 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010095 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010096 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010097 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010098 ctxt->context->doc = bakd;
10099 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010100 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010101 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010102 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010103 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010104 if (op->value)
10105 equal = xmlXPathEqualValues(ctxt);
10106 else
10107 equal = xmlXPathNotEqualValues(ctxt);
10108 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010109 return (total);
10110 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010111 bakd = ctxt->context->doc;
10112 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010113 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010114 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010115 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010116 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010117 ctxt->context->doc = bakd;
10118 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010119 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010120 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010121 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010122 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010123 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10124 valuePush(ctxt, xmlXPathNewBoolean(ret));
10125 return (total);
10126 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010127 bakd = ctxt->context->doc;
10128 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010129 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010130 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010131 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010132 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010133 if (op->ch2 != -1) {
10134 ctxt->context->doc = bakd;
10135 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010136 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010137 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010138 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010139 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010140 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010141 if (op->value == 0)
10142 xmlXPathSubValues(ctxt);
10143 else if (op->value == 1)
10144 xmlXPathAddValues(ctxt);
10145 else if (op->value == 2)
10146 xmlXPathValueFlipSign(ctxt);
10147 else if (op->value == 3) {
10148 CAST_TO_NUMBER;
10149 CHECK_TYPE0(XPATH_NUMBER);
10150 }
10151 return (total);
10152 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010153 bakd = ctxt->context->doc;
10154 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010155 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010156 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010157 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010158 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010159 ctxt->context->doc = bakd;
10160 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010161 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010162 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010163 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010164 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010165 if (op->value == 0)
10166 xmlXPathMultValues(ctxt);
10167 else if (op->value == 1)
10168 xmlXPathDivValues(ctxt);
10169 else if (op->value == 2)
10170 xmlXPathModValues(ctxt);
10171 return (total);
10172 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010173 bakd = ctxt->context->doc;
10174 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010175 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010176 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010177 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010178 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010179 ctxt->context->doc = bakd;
10180 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010181 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010182 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010183 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010184 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010185 CHECK_TYPE0(XPATH_NODESET);
10186 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010187
Daniel Veillardf06307e2001-07-03 10:35:50 +000010188 CHECK_TYPE0(XPATH_NODESET);
10189 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010190
Daniel Veillardf06307e2001-07-03 10:35:50 +000010191 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10192 arg2->nodesetval);
10193 valuePush(ctxt, arg1);
10194 xmlXPathFreeObject(arg2);
10195 return (total);
10196 case XPATH_OP_ROOT:
10197 xmlXPathRoot(ctxt);
10198 return (total);
10199 case XPATH_OP_NODE:
10200 if (op->ch1 != -1)
10201 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010202 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010203 if (op->ch2 != -1)
10204 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010205 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010206 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10207 return (total);
10208 case XPATH_OP_RESET:
10209 if (op->ch1 != -1)
10210 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010211 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010212 if (op->ch2 != -1)
10213 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010214 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010215 ctxt->context->node = NULL;
10216 return (total);
10217 case XPATH_OP_COLLECT:{
10218 if (op->ch1 == -1)
10219 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010220
Daniel Veillardf06307e2001-07-03 10:35:50 +000010221 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010222 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010223
Daniel Veillardf06307e2001-07-03 10:35:50 +000010224 /*
10225 * Optimization for [n] selection where n is a number
10226 */
10227 if ((op->ch2 != -1) &&
10228 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10229 (comp->steps[op->ch2].ch1 == -1) &&
10230 (comp->steps[op->ch2].ch2 != -1) &&
10231 (comp->steps[comp->steps[op->ch2].ch2].op ==
10232 XPATH_OP_VALUE)) {
10233 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010234
Daniel Veillardf06307e2001-07-03 10:35:50 +000010235 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10236 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10237 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010238
Daniel Veillardf06307e2001-07-03 10:35:50 +000010239 if (val->floatval == (float) indx) {
10240 total +=
10241 xmlXPathNodeCollectAndTestNth(ctxt, op,
10242 indx, NULL,
10243 NULL);
10244 return (total);
10245 }
10246 }
10247 }
10248 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10249 return (total);
10250 }
10251 case XPATH_OP_VALUE:
10252 valuePush(ctxt,
10253 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10254 return (total);
10255 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010256 xmlXPathObjectPtr val;
10257
Daniel Veillardf06307e2001-07-03 10:35:50 +000010258 if (op->ch1 != -1)
10259 total +=
10260 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010261 if (op->value5 == NULL) {
10262 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10263 if (val == NULL) {
10264 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10265 return(0);
10266 }
10267 valuePush(ctxt, val);
10268 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010269 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010270
Daniel Veillardf06307e2001-07-03 10:35:50 +000010271 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10272 if (URI == NULL) {
10273 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010274 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010275 op->value4, op->value5);
10276 return (total);
10277 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010278 val = xmlXPathVariableLookupNS(ctxt->context,
10279 op->value4, URI);
10280 if (val == NULL) {
10281 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10282 return(0);
10283 }
10284 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010285 }
10286 return (total);
10287 }
10288 case XPATH_OP_FUNCTION:{
10289 xmlXPathFunction func;
10290 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010291 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010292
10293 if (op->ch1 != -1)
10294 total +=
10295 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010296 if (ctxt->valueNr < op->value) {
10297 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010298 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010299 ctxt->error = XPATH_INVALID_OPERAND;
10300 return (total);
10301 }
10302 for (i = 0; i < op->value; i++)
10303 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10304 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010305 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010306 ctxt->error = XPATH_INVALID_OPERAND;
10307 return (total);
10308 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010309 if (op->cache != NULL)
10310 func = (xmlXPathFunction) op->cache;
10311 else {
10312 const xmlChar *URI = NULL;
10313
10314 if (op->value5 == NULL)
10315 func =
10316 xmlXPathFunctionLookup(ctxt->context,
10317 op->value4);
10318 else {
10319 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10320 if (URI == NULL) {
10321 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010322 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010323 op->value4, op->value5);
10324 return (total);
10325 }
10326 func = xmlXPathFunctionLookupNS(ctxt->context,
10327 op->value4, URI);
10328 }
10329 if (func == NULL) {
10330 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010331 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010332 op->value4);
10333 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010334 }
10335 op->cache = (void *) func;
10336 op->cacheURI = (void *) URI;
10337 }
10338 oldFunc = ctxt->context->function;
10339 oldFuncURI = ctxt->context->functionURI;
10340 ctxt->context->function = op->value4;
10341 ctxt->context->functionURI = op->cacheURI;
10342 func(ctxt, op->value);
10343 ctxt->context->function = oldFunc;
10344 ctxt->context->functionURI = oldFuncURI;
10345 return (total);
10346 }
10347 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010348 bakd = ctxt->context->doc;
10349 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010350 if (op->ch1 != -1)
10351 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010352 ctxt->context->doc = bakd;
10353 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010354 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010355 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010356 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010357 ctxt->context->doc = bakd;
10358 ctxt->context->node = bak;
10359 CHECK_ERROR0;
10360 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010361 return (total);
10362 case XPATH_OP_PREDICATE:
10363 case XPATH_OP_FILTER:{
10364 xmlXPathObjectPtr res;
10365 xmlXPathObjectPtr obj, tmp;
10366 xmlNodeSetPtr newset = NULL;
10367 xmlNodeSetPtr oldset;
10368 xmlNodePtr oldnode;
10369 int i;
10370
10371 /*
10372 * Optimization for ()[1] selection i.e. the first elem
10373 */
10374 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10375 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10376 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10377 xmlXPathObjectPtr val;
10378
10379 val = comp->steps[op->ch2].value4;
10380 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10381 (val->floatval == 1.0)) {
10382 xmlNodePtr first = NULL;
10383
10384 total +=
10385 xmlXPathCompOpEvalFirst(ctxt,
10386 &comp->steps[op->ch1],
10387 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010388 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010389 /*
10390 * The nodeset should be in document order,
10391 * Keep only the first value
10392 */
10393 if ((ctxt->value != NULL) &&
10394 (ctxt->value->type == XPATH_NODESET) &&
10395 (ctxt->value->nodesetval != NULL) &&
10396 (ctxt->value->nodesetval->nodeNr > 1))
10397 ctxt->value->nodesetval->nodeNr = 1;
10398 return (total);
10399 }
10400 }
10401 /*
10402 * Optimization for ()[last()] selection i.e. the last elem
10403 */
10404 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10405 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10406 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10407 int f = comp->steps[op->ch2].ch1;
10408
10409 if ((f != -1) &&
10410 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10411 (comp->steps[f].value5 == NULL) &&
10412 (comp->steps[f].value == 0) &&
10413 (comp->steps[f].value4 != NULL) &&
10414 (xmlStrEqual
10415 (comp->steps[f].value4, BAD_CAST "last"))) {
10416 xmlNodePtr last = NULL;
10417
10418 total +=
10419 xmlXPathCompOpEvalLast(ctxt,
10420 &comp->steps[op->ch1],
10421 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010422 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010423 /*
10424 * The nodeset should be in document order,
10425 * Keep only the last value
10426 */
10427 if ((ctxt->value != NULL) &&
10428 (ctxt->value->type == XPATH_NODESET) &&
10429 (ctxt->value->nodesetval != NULL) &&
10430 (ctxt->value->nodesetval->nodeTab != NULL) &&
10431 (ctxt->value->nodesetval->nodeNr > 1)) {
10432 ctxt->value->nodesetval->nodeTab[0] =
10433 ctxt->value->nodesetval->nodeTab[ctxt->
10434 value->
10435 nodesetval->
10436 nodeNr -
10437 1];
10438 ctxt->value->nodesetval->nodeNr = 1;
10439 }
10440 return (total);
10441 }
10442 }
10443
10444 if (op->ch1 != -1)
10445 total +=
10446 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010447 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010448 if (op->ch2 == -1)
10449 return (total);
10450 if (ctxt->value == NULL)
10451 return (total);
10452
10453 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010454
10455#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010456 /*
10457 * Hum are we filtering the result of an XPointer expression
10458 */
10459 if (ctxt->value->type == XPATH_LOCATIONSET) {
10460 xmlLocationSetPtr newlocset = NULL;
10461 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010462
Daniel Veillardf06307e2001-07-03 10:35:50 +000010463 /*
10464 * Extract the old locset, and then evaluate the result of the
10465 * expression for all the element in the locset. use it to grow
10466 * up a new locset.
10467 */
10468 CHECK_TYPE0(XPATH_LOCATIONSET);
10469 obj = valuePop(ctxt);
10470 oldlocset = obj->user;
10471 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010472
Daniel Veillardf06307e2001-07-03 10:35:50 +000010473 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10474 ctxt->context->contextSize = 0;
10475 ctxt->context->proximityPosition = 0;
10476 if (op->ch2 != -1)
10477 total +=
10478 xmlXPathCompOpEval(ctxt,
10479 &comp->steps[op->ch2]);
10480 res = valuePop(ctxt);
10481 if (res != NULL)
10482 xmlXPathFreeObject(res);
10483 valuePush(ctxt, obj);
10484 CHECK_ERROR0;
10485 return (total);
10486 }
10487 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010488
Daniel Veillardf06307e2001-07-03 10:35:50 +000010489 for (i = 0; i < oldlocset->locNr; i++) {
10490 /*
10491 * Run the evaluation with a node list made of a
10492 * single item in the nodelocset.
10493 */
10494 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010495 ctxt->context->contextSize = oldlocset->locNr;
10496 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010497 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10498 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010499
Daniel Veillardf06307e2001-07-03 10:35:50 +000010500 if (op->ch2 != -1)
10501 total +=
10502 xmlXPathCompOpEval(ctxt,
10503 &comp->steps[op->ch2]);
10504 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010505
Daniel Veillardf06307e2001-07-03 10:35:50 +000010506 /*
10507 * The result of the evaluation need to be tested to
10508 * decided whether the filter succeeded or not
10509 */
10510 res = valuePop(ctxt);
10511 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10512 xmlXPtrLocationSetAdd(newlocset,
10513 xmlXPathObjectCopy
10514 (oldlocset->locTab[i]));
10515 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010516
Daniel Veillardf06307e2001-07-03 10:35:50 +000010517 /*
10518 * Cleanup
10519 */
10520 if (res != NULL)
10521 xmlXPathFreeObject(res);
10522 if (ctxt->value == tmp) {
10523 res = valuePop(ctxt);
10524 xmlXPathFreeObject(res);
10525 }
10526
10527 ctxt->context->node = NULL;
10528 }
10529
10530 /*
10531 * The result is used as the new evaluation locset.
10532 */
10533 xmlXPathFreeObject(obj);
10534 ctxt->context->node = NULL;
10535 ctxt->context->contextSize = -1;
10536 ctxt->context->proximityPosition = -1;
10537 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10538 ctxt->context->node = oldnode;
10539 return (total);
10540 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010541#endif /* LIBXML_XPTR_ENABLED */
10542
Daniel Veillardf06307e2001-07-03 10:35:50 +000010543 /*
10544 * Extract the old set, and then evaluate the result of the
10545 * expression for all the element in the set. use it to grow
10546 * up a new set.
10547 */
10548 CHECK_TYPE0(XPATH_NODESET);
10549 obj = valuePop(ctxt);
10550 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010551
Daniel Veillardf06307e2001-07-03 10:35:50 +000010552 oldnode = ctxt->context->node;
10553 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010554
Daniel Veillardf06307e2001-07-03 10:35:50 +000010555 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10556 ctxt->context->contextSize = 0;
10557 ctxt->context->proximityPosition = 0;
10558 if (op->ch2 != -1)
10559 total +=
10560 xmlXPathCompOpEval(ctxt,
10561 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010562 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010563 res = valuePop(ctxt);
10564 if (res != NULL)
10565 xmlXPathFreeObject(res);
10566 valuePush(ctxt, obj);
10567 ctxt->context->node = oldnode;
10568 CHECK_ERROR0;
10569 } else {
10570 /*
10571 * Initialize the new set.
10572 */
10573 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010574
Daniel Veillardf06307e2001-07-03 10:35:50 +000010575 for (i = 0; i < oldset->nodeNr; i++) {
10576 /*
10577 * Run the evaluation with a node list made of
10578 * a single item in the nodeset.
10579 */
10580 ctxt->context->node = oldset->nodeTab[i];
10581 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10582 valuePush(ctxt, tmp);
10583 ctxt->context->contextSize = oldset->nodeNr;
10584 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010585
Daniel Veillardf06307e2001-07-03 10:35:50 +000010586 if (op->ch2 != -1)
10587 total +=
10588 xmlXPathCompOpEval(ctxt,
10589 &comp->steps[op->ch2]);
10590 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010591
Daniel Veillardf06307e2001-07-03 10:35:50 +000010592 /*
William M. Brack08171912003-12-29 02:52:11 +000010593 * The result of the evaluation needs to be tested to
10594 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010595 */
10596 res = valuePop(ctxt);
10597 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10598 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10599 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010600
Daniel Veillardf06307e2001-07-03 10:35:50 +000010601 /*
10602 * Cleanup
10603 */
10604 if (res != NULL)
10605 xmlXPathFreeObject(res);
10606 if (ctxt->value == tmp) {
10607 res = valuePop(ctxt);
10608 xmlXPathFreeObject(res);
10609 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010610
Daniel Veillardf06307e2001-07-03 10:35:50 +000010611 ctxt->context->node = NULL;
10612 }
10613
10614 /*
10615 * The result is used as the new evaluation set.
10616 */
10617 xmlXPathFreeObject(obj);
10618 ctxt->context->node = NULL;
10619 ctxt->context->contextSize = -1;
10620 ctxt->context->proximityPosition = -1;
10621 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10622 }
10623 ctxt->context->node = oldnode;
10624 return (total);
10625 }
10626 case XPATH_OP_SORT:
10627 if (op->ch1 != -1)
10628 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010629 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010630 if ((ctxt->value != NULL) &&
10631 (ctxt->value->type == XPATH_NODESET) &&
10632 (ctxt->value->nodesetval != NULL))
10633 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10634 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010635#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010636 case XPATH_OP_RANGETO:{
10637 xmlXPathObjectPtr range;
10638 xmlXPathObjectPtr res, obj;
10639 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010640 xmlLocationSetPtr newlocset = NULL;
10641 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010642 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000010643 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010644
Daniel Veillardf06307e2001-07-03 10:35:50 +000010645 if (op->ch1 != -1)
10646 total +=
10647 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10648 if (op->ch2 == -1)
10649 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010650
William M. Brack08171912003-12-29 02:52:11 +000010651 if (ctxt->value->type == XPATH_LOCATIONSET) {
10652 /*
10653 * Extract the old locset, and then evaluate the result of the
10654 * expression for all the element in the locset. use it to grow
10655 * up a new locset.
10656 */
10657 CHECK_TYPE0(XPATH_LOCATIONSET);
10658 obj = valuePop(ctxt);
10659 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010660
William M. Brack08171912003-12-29 02:52:11 +000010661 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000010662 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000010663 ctxt->context->contextSize = 0;
10664 ctxt->context->proximityPosition = 0;
10665 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10666 res = valuePop(ctxt);
10667 if (res != NULL)
10668 xmlXPathFreeObject(res);
10669 valuePush(ctxt, obj);
10670 CHECK_ERROR0;
10671 return (total);
10672 }
10673 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010674
William M. Brack08171912003-12-29 02:52:11 +000010675 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010676 /*
William M. Brack08171912003-12-29 02:52:11 +000010677 * Run the evaluation with a node list made of a
10678 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010679 */
William M. Brackf7eb7942003-12-31 07:59:17 +000010680 ctxt->context->node = oldlocset->locTab[i]->user;
10681 ctxt->context->contextSize = oldlocset->locNr;
10682 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010683 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10684 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010685
Daniel Veillardf06307e2001-07-03 10:35:50 +000010686 if (op->ch2 != -1)
10687 total +=
10688 xmlXPathCompOpEval(ctxt,
10689 &comp->steps[op->ch2]);
10690 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010691
Daniel Veillardf06307e2001-07-03 10:35:50 +000010692 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000010693 if (res->type == XPATH_LOCATIONSET) {
10694 xmlLocationSetPtr rloc =
10695 (xmlLocationSetPtr)res->user;
10696 for (j=0; j<rloc->locNr; j++) {
10697 range = xmlXPtrNewRange(
10698 oldlocset->locTab[i]->user,
10699 oldlocset->locTab[i]->index,
10700 rloc->locTab[j]->user2,
10701 rloc->locTab[j]->index2);
10702 if (range != NULL) {
10703 xmlXPtrLocationSetAdd(newlocset, range);
10704 }
10705 }
10706 } else {
10707 range = xmlXPtrNewRangeNodeObject(
10708 (xmlNodePtr)oldlocset->locTab[i]->user, res);
10709 if (range != NULL) {
10710 xmlXPtrLocationSetAdd(newlocset,range);
10711 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010712 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010713
Daniel Veillardf06307e2001-07-03 10:35:50 +000010714 /*
10715 * Cleanup
10716 */
10717 if (res != NULL)
10718 xmlXPathFreeObject(res);
10719 if (ctxt->value == tmp) {
10720 res = valuePop(ctxt);
10721 xmlXPathFreeObject(res);
10722 }
10723
10724 ctxt->context->node = NULL;
10725 }
William M. Brack72ee48d2003-12-30 08:30:19 +000010726 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000010727 CHECK_TYPE0(XPATH_NODESET);
10728 obj = valuePop(ctxt);
10729 oldset = obj->nodesetval;
10730 ctxt->context->node = NULL;
10731
10732 newlocset = xmlXPtrLocationSetCreate(NULL);
10733
10734 if (oldset != NULL) {
10735 for (i = 0; i < oldset->nodeNr; i++) {
10736 /*
10737 * Run the evaluation with a node list made of a single item
10738 * in the nodeset.
10739 */
10740 ctxt->context->node = oldset->nodeTab[i];
10741 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10742 valuePush(ctxt, tmp);
10743
10744 if (op->ch2 != -1)
10745 total +=
10746 xmlXPathCompOpEval(ctxt,
10747 &comp->steps[op->ch2]);
10748 CHECK_ERROR0;
10749
William M. Brack08171912003-12-29 02:52:11 +000010750 res = valuePop(ctxt);
10751 range =
10752 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10753 res);
10754 if (range != NULL) {
10755 xmlXPtrLocationSetAdd(newlocset, range);
10756 }
10757
10758 /*
10759 * Cleanup
10760 */
10761 if (res != NULL)
10762 xmlXPathFreeObject(res);
10763 if (ctxt->value == tmp) {
10764 res = valuePop(ctxt);
10765 xmlXPathFreeObject(res);
10766 }
10767
10768 ctxt->context->node = NULL;
10769 }
10770 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010771 }
10772
10773 /*
10774 * The result is used as the new evaluation set.
10775 */
10776 xmlXPathFreeObject(obj);
10777 ctxt->context->node = NULL;
10778 ctxt->context->contextSize = -1;
10779 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010780 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010781 return (total);
10782 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010783#endif /* LIBXML_XPTR_ENABLED */
10784 }
10785 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010786 "XPath: unknown precompiled operation %d\n", op->op);
10787 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010788}
10789
10790/**
10791 * xmlXPathRunEval:
10792 * @ctxt: the XPath parser context with the compiled expression
10793 *
10794 * Evaluate the Precompiled XPath expression in the given context.
10795 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010796static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010797xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10798 xmlXPathCompExprPtr comp;
10799
10800 if ((ctxt == NULL) || (ctxt->comp == NULL))
10801 return;
10802
10803 if (ctxt->valueTab == NULL) {
10804 /* Allocate the value stack */
10805 ctxt->valueTab = (xmlXPathObjectPtr *)
10806 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10807 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010808 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010809 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010810 }
10811 ctxt->valueNr = 0;
10812 ctxt->valueMax = 10;
10813 ctxt->value = NULL;
10814 }
10815 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010816 if(comp->last < 0) {
10817 xmlGenericError(xmlGenericErrorContext,
10818 "xmlXPathRunEval: last is less than zero\n");
10819 return;
10820 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010821 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10822}
10823
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010824/************************************************************************
10825 * *
10826 * Public interfaces *
10827 * *
10828 ************************************************************************/
10829
10830/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010831 * xmlXPathEvalPredicate:
10832 * @ctxt: the XPath context
10833 * @res: the Predicate Expression evaluation result
10834 *
10835 * Evaluate a predicate result for the current node.
10836 * A PredicateExpr is evaluated by evaluating the Expr and converting
10837 * the result to a boolean. If the result is a number, the result will
10838 * be converted to true if the number is equal to the position of the
10839 * context node in the context node list (as returned by the position
10840 * function) and will be converted to false otherwise; if the result
10841 * is not a number, then the result will be converted as if by a call
10842 * to the boolean function.
10843 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010844 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010845 */
10846int
10847xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10848 if (res == NULL) return(0);
10849 switch (res->type) {
10850 case XPATH_BOOLEAN:
10851 return(res->boolval);
10852 case XPATH_NUMBER:
10853 return(res->floatval == ctxt->proximityPosition);
10854 case XPATH_NODESET:
10855 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010856 if (res->nodesetval == NULL)
10857 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010858 return(res->nodesetval->nodeNr != 0);
10859 case XPATH_STRING:
10860 return((res->stringval != NULL) &&
10861 (xmlStrlen(res->stringval) != 0));
10862 default:
10863 STRANGE
10864 }
10865 return(0);
10866}
10867
10868/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010869 * xmlXPathEvaluatePredicateResult:
10870 * @ctxt: the XPath Parser context
10871 * @res: the Predicate Expression evaluation result
10872 *
10873 * Evaluate a predicate result for the current node.
10874 * A PredicateExpr is evaluated by evaluating the Expr and converting
10875 * the result to a boolean. If the result is a number, the result will
10876 * be converted to true if the number is equal to the position of the
10877 * context node in the context node list (as returned by the position
10878 * function) and will be converted to false otherwise; if the result
10879 * is not a number, then the result will be converted as if by a call
10880 * to the boolean function.
10881 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010882 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010883 */
10884int
10885xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10886 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->context->proximityPosition);
10893 case XPATH_NODESET:
10894 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010895 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010896 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010897 return(res->nodesetval->nodeNr != 0);
10898 case XPATH_STRING:
10899 return((res->stringval != NULL) &&
10900 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000010901#ifdef LIBXML_XPTR_ENABLED
10902 case XPATH_LOCATIONSET:{
10903 xmlLocationSetPtr ptr = res->user;
10904 if (ptr == NULL)
10905 return(0);
10906 return (ptr->locNr != 0);
10907 }
10908#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010909 default:
10910 STRANGE
10911 }
10912 return(0);
10913}
10914
10915/**
Daniel Veillard4773df22004-01-23 13:15:13 +000010916 * xmlXPathCtxtCompile:
10917 * @ctxt: an XPath context
10918 * @str: the XPath expression
10919 *
10920 * Compile an XPath expression
10921 *
10922 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
10923 * the caller has to free the object.
10924 */
10925xmlXPathCompExprPtr
10926xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
10927 xmlXPathParserContextPtr pctxt;
10928 xmlXPathCompExprPtr comp;
10929
10930 xmlXPathInit();
10931
10932 pctxt = xmlXPathNewParserContext(str, ctxt);
10933 xmlXPathCompileExpr(pctxt);
10934
10935 if( pctxt->error != XPATH_EXPRESSION_OK )
10936 {
10937 xmlXPathFreeParserContext(pctxt);
10938 return (0);
10939 }
10940
10941 if (*pctxt->cur != 0) {
10942 /*
10943 * aleksey: in some cases this line prints *second* error message
10944 * (see bug #78858) and probably this should be fixed.
10945 * However, we are not sure that all error messages are printed
10946 * out in other places. It's not critical so we leave it as-is for now
10947 */
10948 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10949 comp = NULL;
10950 } else {
10951 comp = pctxt->comp;
10952 pctxt->comp = NULL;
10953 }
10954 xmlXPathFreeParserContext(pctxt);
10955 if (comp != NULL) {
10956 comp->expr = xmlStrdup(str);
10957#ifdef DEBUG_EVAL_COUNTS
10958 comp->string = xmlStrdup(str);
10959 comp->nb = 0;
10960#endif
10961 }
10962 return(comp);
10963}
10964
10965/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010966 * xmlXPathCompile:
10967 * @str: the XPath expression
10968 *
10969 * Compile an XPath expression
10970 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010971 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010972 * the caller has to free the object.
10973 */
10974xmlXPathCompExprPtr
10975xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000010976 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010977}
10978
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010979/**
10980 * xmlXPathCompiledEval:
10981 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010982 * @ctx: the XPath context
10983 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010984 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010985 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010986 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010987 * the caller has to free the object.
10988 */
10989xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010990xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010991 xmlXPathParserContextPtr ctxt;
10992 xmlXPathObjectPtr res, tmp, init = NULL;
10993 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010994#ifndef LIBXML_THREAD_ENABLED
10995 static int reentance = 0;
10996#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010997
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010998 if ((comp == NULL) || (ctx == NULL))
10999 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011000 xmlXPathInit();
11001
11002 CHECK_CONTEXT(ctx)
11003
Daniel Veillard81463942001-10-16 12:34:39 +000011004#ifndef LIBXML_THREAD_ENABLED
11005 reentance++;
11006 if (reentance > 1)
11007 xmlXPathDisableOptimizer = 1;
11008#endif
11009
Daniel Veillardf06307e2001-07-03 10:35:50 +000011010#ifdef DEBUG_EVAL_COUNTS
11011 comp->nb++;
11012 if ((comp->string != NULL) && (comp->nb > 100)) {
11013 fprintf(stderr, "100 x %s\n", comp->string);
11014 comp->nb = 0;
11015 }
11016#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011017 ctxt = xmlXPathCompParserContext(comp, ctx);
11018 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011019
11020 if (ctxt->value == NULL) {
11021 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011022 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011023 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011024 } else {
11025 res = valuePop(ctxt);
11026 }
11027
Daniel Veillardf06307e2001-07-03 10:35:50 +000011028
Owen Taylor3473f882001-02-23 17:55:21 +000011029 do {
11030 tmp = valuePop(ctxt);
11031 if (tmp != NULL) {
11032 if (tmp != init)
11033 stack++;
11034 xmlXPathFreeObject(tmp);
11035 }
11036 } while (tmp != NULL);
11037 if ((stack != 0) && (res != NULL)) {
11038 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011039 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011040 stack);
11041 }
11042 if (ctxt->error != XPATH_EXPRESSION_OK) {
11043 xmlXPathFreeObject(res);
11044 res = NULL;
11045 }
11046
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011047
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011048 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011049 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011050#ifndef LIBXML_THREAD_ENABLED
11051 reentance--;
11052#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011053 return(res);
11054}
11055
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011056/**
11057 * xmlXPathEvalExpr:
11058 * @ctxt: the XPath Parser context
11059 *
11060 * Parse and evaluate an XPath expression in the given context,
11061 * then push the result on the context stack
11062 */
11063void
11064xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
11065 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011066 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011067 xmlXPathRunEval(ctxt);
11068}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011069
11070/**
11071 * xmlXPathEval:
11072 * @str: the XPath expression
11073 * @ctx: the XPath context
11074 *
11075 * Evaluate the XPath Location Path in the given context.
11076 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011077 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011078 * the caller has to free the object.
11079 */
11080xmlXPathObjectPtr
11081xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11082 xmlXPathParserContextPtr ctxt;
11083 xmlXPathObjectPtr res, tmp, init = NULL;
11084 int stack = 0;
11085
11086 xmlXPathInit();
11087
11088 CHECK_CONTEXT(ctx)
11089
11090 ctxt = xmlXPathNewParserContext(str, ctx);
11091 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011092
11093 if (ctxt->value == NULL) {
11094 xmlGenericError(xmlGenericErrorContext,
11095 "xmlXPathEval: evaluation failed\n");
11096 res = NULL;
11097 } else if (*ctxt->cur != 0) {
11098 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11099 res = NULL;
11100 } else {
11101 res = valuePop(ctxt);
11102 }
11103
11104 do {
11105 tmp = valuePop(ctxt);
11106 if (tmp != NULL) {
11107 if (tmp != init)
11108 stack++;
11109 xmlXPathFreeObject(tmp);
11110 }
11111 } while (tmp != NULL);
11112 if ((stack != 0) && (res != NULL)) {
11113 xmlGenericError(xmlGenericErrorContext,
11114 "xmlXPathEval: %d object left on the stack\n",
11115 stack);
11116 }
11117 if (ctxt->error != XPATH_EXPRESSION_OK) {
11118 xmlXPathFreeObject(res);
11119 res = NULL;
11120 }
11121
Owen Taylor3473f882001-02-23 17:55:21 +000011122 xmlXPathFreeParserContext(ctxt);
11123 return(res);
11124}
11125
11126/**
11127 * xmlXPathEvalExpression:
11128 * @str: the XPath expression
11129 * @ctxt: the XPath context
11130 *
11131 * Evaluate the XPath expression in the given context.
11132 *
11133 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11134 * the caller has to free the object.
11135 */
11136xmlXPathObjectPtr
11137xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11138 xmlXPathParserContextPtr pctxt;
11139 xmlXPathObjectPtr res, tmp;
11140 int stack = 0;
11141
11142 xmlXPathInit();
11143
11144 CHECK_CONTEXT(ctxt)
11145
11146 pctxt = xmlXPathNewParserContext(str, ctxt);
11147 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011148
11149 if (*pctxt->cur != 0) {
11150 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11151 res = NULL;
11152 } else {
11153 res = valuePop(pctxt);
11154 }
11155 do {
11156 tmp = valuePop(pctxt);
11157 if (tmp != NULL) {
11158 xmlXPathFreeObject(tmp);
11159 stack++;
11160 }
11161 } while (tmp != NULL);
11162 if ((stack != 0) && (res != NULL)) {
11163 xmlGenericError(xmlGenericErrorContext,
11164 "xmlXPathEvalExpression: %d object left on the stack\n",
11165 stack);
11166 }
11167 xmlXPathFreeParserContext(pctxt);
11168 return(res);
11169}
11170
Daniel Veillard42766c02002-08-22 20:52:17 +000011171/************************************************************************
11172 * *
11173 * Extra functions not pertaining to the XPath spec *
11174 * *
11175 ************************************************************************/
11176/**
11177 * xmlXPathEscapeUriFunction:
11178 * @ctxt: the XPath Parser context
11179 * @nargs: the number of arguments
11180 *
11181 * Implement the escape-uri() XPath function
11182 * string escape-uri(string $str, bool $escape-reserved)
11183 *
11184 * This function applies the URI escaping rules defined in section 2 of [RFC
11185 * 2396] to the string supplied as $uri-part, which typically represents all
11186 * or part of a URI. The effect of the function is to replace any special
11187 * character in the string by an escape sequence of the form %xx%yy...,
11188 * where xxyy... is the hexadecimal representation of the octets used to
11189 * represent the character in UTF-8.
11190 *
11191 * The set of characters that are escaped depends on the setting of the
11192 * boolean argument $escape-reserved.
11193 *
11194 * If $escape-reserved is true, all characters are escaped other than lower
11195 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11196 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11197 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11198 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11199 * A-F).
11200 *
11201 * If $escape-reserved is false, the behavior differs in that characters
11202 * referred to in [RFC 2396] as reserved characters are not escaped. These
11203 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11204 *
11205 * [RFC 2396] does not define whether escaped URIs should use lower case or
11206 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11207 * compared using string comparison functions, this function must always use
11208 * the upper-case letters A-F.
11209 *
11210 * Generally, $escape-reserved should be set to true when escaping a string
11211 * that is to form a single part of a URI, and to false when escaping an
11212 * entire URI or URI reference.
11213 *
11214 * In the case of non-ascii characters, the string is encoded according to
11215 * utf-8 and then converted according to RFC 2396.
11216 *
11217 * Examples
11218 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11219 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11220 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11221 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11222 *
11223 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011224static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011225xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11226 xmlXPathObjectPtr str;
11227 int escape_reserved;
11228 xmlBufferPtr target;
11229 xmlChar *cptr;
11230 xmlChar escape[4];
11231
11232 CHECK_ARITY(2);
11233
11234 escape_reserved = xmlXPathPopBoolean(ctxt);
11235
11236 CAST_TO_STRING;
11237 str = valuePop(ctxt);
11238
11239 target = xmlBufferCreate();
11240
11241 escape[0] = '%';
11242 escape[3] = 0;
11243
11244 if (target) {
11245 for (cptr = str->stringval; *cptr; cptr++) {
11246 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11247 (*cptr >= 'a' && *cptr <= 'z') ||
11248 (*cptr >= '0' && *cptr <= '9') ||
11249 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11250 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11251 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11252 (*cptr == '%' &&
11253 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11254 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11255 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11256 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11257 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11258 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11259 (!escape_reserved &&
11260 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11261 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11262 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11263 *cptr == ','))) {
11264 xmlBufferAdd(target, cptr, 1);
11265 } else {
11266 if ((*cptr >> 4) < 10)
11267 escape[1] = '0' + (*cptr >> 4);
11268 else
11269 escape[1] = 'A' - 10 + (*cptr >> 4);
11270 if ((*cptr & 0xF) < 10)
11271 escape[2] = '0' + (*cptr & 0xF);
11272 else
11273 escape[2] = 'A' - 10 + (*cptr & 0xF);
11274
11275 xmlBufferAdd(target, &escape[0], 3);
11276 }
11277 }
11278 }
11279 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11280 xmlBufferFree(target);
11281 xmlXPathFreeObject(str);
11282}
11283
Owen Taylor3473f882001-02-23 17:55:21 +000011284/**
11285 * xmlXPathRegisterAllFunctions:
11286 * @ctxt: the XPath context
11287 *
11288 * Registers all default XPath functions in this context
11289 */
11290void
11291xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11292{
11293 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11294 xmlXPathBooleanFunction);
11295 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11296 xmlXPathCeilingFunction);
11297 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11298 xmlXPathCountFunction);
11299 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11300 xmlXPathConcatFunction);
11301 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11302 xmlXPathContainsFunction);
11303 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11304 xmlXPathIdFunction);
11305 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11306 xmlXPathFalseFunction);
11307 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11308 xmlXPathFloorFunction);
11309 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11310 xmlXPathLastFunction);
11311 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11312 xmlXPathLangFunction);
11313 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11314 xmlXPathLocalNameFunction);
11315 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11316 xmlXPathNotFunction);
11317 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11318 xmlXPathNameFunction);
11319 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11320 xmlXPathNamespaceURIFunction);
11321 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11322 xmlXPathNormalizeFunction);
11323 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11324 xmlXPathNumberFunction);
11325 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11326 xmlXPathPositionFunction);
11327 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11328 xmlXPathRoundFunction);
11329 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11330 xmlXPathStringFunction);
11331 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11332 xmlXPathStringLengthFunction);
11333 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11334 xmlXPathStartsWithFunction);
11335 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11336 xmlXPathSubstringFunction);
11337 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11338 xmlXPathSubstringBeforeFunction);
11339 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11340 xmlXPathSubstringAfterFunction);
11341 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11342 xmlXPathSumFunction);
11343 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11344 xmlXPathTrueFunction);
11345 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11346 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011347
11348 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11349 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11350 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011351}
11352
11353#endif /* LIBXML_XPATH_ENABLED */