blob: 09869863297101c8988ebf76bd5f9b9fecd9673a [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
Owen Taylor3473f882001-02-23 17:55:21 +000031#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000034#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000035#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#endif
Owen Taylor3473f882001-02-23 17:55:21 +000037
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000052#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000053#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000054
Daniel Veillardd96f6d32003-10-07 21:25:12 +000055#define TODO \
56 xmlGenericError(xmlGenericErrorContext, \
57 "Unimplemented block at %s:%d\n", \
58 __FILE__, __LINE__);
59
Daniel Veillard4432df22003-09-28 18:58:27 +000060#if defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000061/************************************************************************
62 * *
63 * Floating point stuff *
64 * *
65 ************************************************************************/
66
Daniel Veillardc0631a62001-09-20 13:56:06 +000067#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000068#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000069#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000070#include "trionan.c"
71
Owen Taylor3473f882001-02-23 17:55:21 +000072/*
Owen Taylor3473f882001-02-23 17:55:21 +000073 * The lack of portability of this section of the libc is annoying !
74 */
75double xmlXPathNAN = 0;
76double xmlXPathPINF = 1;
77double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000078double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000079static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000080
Owen Taylor3473f882001-02-23 17:55:21 +000081/**
82 * xmlXPathInit:
83 *
84 * Initialize the XPath environment
85 */
86void
87xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +000088 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +000089
Bjorn Reese45029602001-08-21 09:23:53 +000090 xmlXPathPINF = trio_pinf();
91 xmlXPathNINF = trio_ninf();
92 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +000093 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +000094
Daniel Veillard20ee8c02001-10-05 09:18:14 +000095 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000096}
97
Daniel Veillardcda96922001-08-21 10:56:31 +000098/**
99 * xmlXPathIsNaN:
100 * @val: a double value
101 *
102 * Provides a portable isnan() function to detect whether a double
103 * is a NotaNumber. Based on trio code
104 * http://sourceforge.net/projects/ctrio/
105 *
106 * Returns 1 if the value is a NaN, 0 otherwise
107 */
108int
109xmlXPathIsNaN(double val) {
110 return(trio_isnan(val));
111}
112
113/**
114 * xmlXPathIsInf:
115 * @val: a double value
116 *
117 * Provides a portable isinf() function to detect whether a double
118 * is a +Infinite or -Infinite. Based on trio code
119 * http://sourceforge.net/projects/ctrio/
120 *
121 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
122 */
123int
124xmlXPathIsInf(double val) {
125 return(trio_isinf(val));
126}
127
Daniel Veillard4432df22003-09-28 18:58:27 +0000128#endif /* SCHEMAS or XPATH */
129#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000130/**
131 * xmlXPathGetSign:
132 * @val: a double value
133 *
134 * Provides a portable function to detect the sign of a double
135 * Modified from trio code
136 * http://sourceforge.net/projects/ctrio/
137 *
138 * Returns 1 if the value is Negative, 0 if positive
139 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000140static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000141xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000142 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000143}
144
145
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000146/*
147 * TODO: when compatibility allows remove all "fake node libxslt" strings
148 * the test should just be name[0] = ' '
149 */
150/* #define DEBUG */
151/* #define DEBUG_STEP */
152/* #define DEBUG_STEP_NTH */
153/* #define DEBUG_EXPR */
154/* #define DEBUG_EVAL_COUNTS */
155
156static xmlNs xmlXPathXMLNamespaceStruct = {
157 NULL,
158 XML_NAMESPACE_DECL,
159 XML_XML_NAMESPACE,
160 BAD_CAST "xml",
161 NULL
162};
163static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
164#ifndef LIBXML_THREAD_ENABLED
165/*
166 * Optimizer is disabled only when threaded apps are detected while
167 * the library ain't compiled for thread safety.
168 */
169static int xmlXPathDisableOptimizer = 0;
170#endif
171
Owen Taylor3473f882001-02-23 17:55:21 +0000172/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000173 * *
174 * Error handling routines *
175 * *
176 ************************************************************************/
177
William M. Brack08171912003-12-29 02:52:11 +0000178/*
179 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
180 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000181static const char *xmlXPathErrorMessages[] = {
182 "Ok\n",
183 "Number encoding\n",
184 "Unfinished literal\n",
185 "Start of literal\n",
186 "Expected $ for variable reference\n",
187 "Undefined variable\n",
188 "Invalid predicate\n",
189 "Invalid expression\n",
190 "Missing closing curly brace\n",
191 "Unregistered function\n",
192 "Invalid operand\n",
193 "Invalid type\n",
194 "Invalid number of arguments\n",
195 "Invalid context size\n",
196 "Invalid context position\n",
197 "Memory allocation error\n",
198 "Syntax error\n",
199 "Resource error\n",
200 "Sub resource error\n",
201 "Undefined namespace prefix\n",
202 "Encoding error\n",
203 "Char out of XML range\n"
204};
205
206
207/**
208 * xmlXPathErrMemory:
209 * @ctxt: an XPath context
210 * @extra: extra informations
211 *
212 * Handle a redefinition of attribute error
213 */
214static void
215xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
216{
217 if (ctxt != NULL) {
218 if (extra) {
219 xmlChar buf[200];
220
221 xmlStrPrintf(buf, 200,
222 BAD_CAST "Memory allocation failed : %s\n",
223 extra);
224 ctxt->lastError.message = (char *) xmlStrdup(buf);
225 } else {
226 ctxt->lastError.message = (char *)
227 xmlStrdup(BAD_CAST "Memory allocation failed\n");
228 }
229 ctxt->lastError.domain = XML_FROM_XPATH;
230 ctxt->lastError.code = XML_ERR_NO_MEMORY;
231 if (ctxt->error != NULL)
232 ctxt->error(ctxt->userData, &ctxt->lastError);
233 } else {
234 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000235 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000236 NULL, NULL, XML_FROM_XPATH,
237 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
238 extra, NULL, NULL, 0, 0,
239 "Memory allocation failed : %s\n", extra);
240 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000241 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000242 NULL, NULL, XML_FROM_XPATH,
243 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
244 NULL, NULL, NULL, 0, 0,
245 "Memory allocation failed\n");
246 }
247}
248
249/**
250 * xmlXPathErrMemory:
251 * @ctxt: an XPath parser context
252 * @extra: extra informations
253 *
254 * Handle a redefinition of attribute error
255 */
256static void
257xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
258{
259 ctxt->error = XPATH_MEMORY_ERROR;
260 if (ctxt == NULL)
261 xmlXPathErrMemory(NULL, extra);
262 else
263 xmlXPathErrMemory(ctxt->context, extra);
264}
265
266/**
267 * xmlXPathErr:
268 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000269 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000270 *
271 * Handle a Relax NG Parsing error
272 */
273void
274xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
275{
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000276 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000277 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000278 NULL, NULL, XML_FROM_XPATH,
279 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
280 XML_ERR_ERROR, NULL, 0,
281 NULL, NULL, NULL, 0, 0,
282 xmlXPathErrorMessages[error]);
283 return;
284 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000285 ctxt->error = error;
286 if (ctxt->context == NULL) {
287 __xmlRaiseError(NULL, NULL, NULL,
288 NULL, NULL, XML_FROM_XPATH,
289 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
290 XML_ERR_ERROR, NULL, 0,
291 (const char *) ctxt->base, NULL, NULL,
292 ctxt->cur - ctxt->base, 0,
293 xmlXPathErrorMessages[error]);
294 return;
295 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000296 ctxt->context->lastError.domain = XML_FROM_XPATH;
297 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
298 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000299 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000300 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
301 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
302 ctxt->context->lastError.node = ctxt->context->debugNode;
303 if (ctxt->context->error != NULL) {
304 ctxt->context->error(ctxt->context->userData,
305 &ctxt->context->lastError);
306 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000307 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000308 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
309 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
310 XML_ERR_ERROR, NULL, 0,
311 (const char *) ctxt->base, NULL, NULL,
312 ctxt->cur - ctxt->base, 0,
313 xmlXPathErrorMessages[error]);
314 }
315
316}
317
318/**
319 * xmlXPatherror:
320 * @ctxt: the XPath Parser context
321 * @file: the file name
322 * @line: the line number
323 * @no: the error number
324 *
325 * Formats an error message.
326 */
327void
328xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
329 int line ATTRIBUTE_UNUSED, int no) {
330 xmlXPathErr(ctxt, no);
331}
332
333
334/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000335 * *
336 * Parser Types *
337 * *
338 ************************************************************************/
339
340/*
341 * Types are private:
342 */
343
344typedef enum {
345 XPATH_OP_END=0,
346 XPATH_OP_AND,
347 XPATH_OP_OR,
348 XPATH_OP_EQUAL,
349 XPATH_OP_CMP,
350 XPATH_OP_PLUS,
351 XPATH_OP_MULT,
352 XPATH_OP_UNION,
353 XPATH_OP_ROOT,
354 XPATH_OP_NODE,
355 XPATH_OP_RESET,
356 XPATH_OP_COLLECT,
357 XPATH_OP_VALUE,
358 XPATH_OP_VARIABLE,
359 XPATH_OP_FUNCTION,
360 XPATH_OP_ARG,
361 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000362 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000363 XPATH_OP_SORT
364#ifdef LIBXML_XPTR_ENABLED
365 ,XPATH_OP_RANGETO
366#endif
367} xmlXPathOp;
368
369typedef enum {
370 AXIS_ANCESTOR = 1,
371 AXIS_ANCESTOR_OR_SELF,
372 AXIS_ATTRIBUTE,
373 AXIS_CHILD,
374 AXIS_DESCENDANT,
375 AXIS_DESCENDANT_OR_SELF,
376 AXIS_FOLLOWING,
377 AXIS_FOLLOWING_SIBLING,
378 AXIS_NAMESPACE,
379 AXIS_PARENT,
380 AXIS_PRECEDING,
381 AXIS_PRECEDING_SIBLING,
382 AXIS_SELF
383} xmlXPathAxisVal;
384
385typedef enum {
386 NODE_TEST_NONE = 0,
387 NODE_TEST_TYPE = 1,
388 NODE_TEST_PI = 2,
389 NODE_TEST_ALL = 3,
390 NODE_TEST_NS = 4,
391 NODE_TEST_NAME = 5
392} xmlXPathTestVal;
393
394typedef enum {
395 NODE_TYPE_NODE = 0,
396 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
397 NODE_TYPE_TEXT = XML_TEXT_NODE,
398 NODE_TYPE_PI = XML_PI_NODE
399} xmlXPathTypeVal;
400
401
402typedef struct _xmlXPathStepOp xmlXPathStepOp;
403typedef xmlXPathStepOp *xmlXPathStepOpPtr;
404struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000405 xmlXPathOp op; /* The identifier of the operation */
406 int ch1; /* First child */
407 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000408 int value;
409 int value2;
410 int value3;
411 void *value4;
412 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000413 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000414 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000415};
416
417struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000418 int nbStep; /* Number of steps in this expression */
419 int maxStep; /* Maximum number of steps allocated */
420 xmlXPathStepOp *steps; /* ops for computation of this expression */
421 int last; /* index of last step in expression */
422 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000423 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000424#ifdef DEBUG_EVAL_COUNTS
425 int nb;
426 xmlChar *string;
427#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000428};
429
430/************************************************************************
431 * *
432 * Parser Type functions *
433 * *
434 ************************************************************************/
435
436/**
437 * xmlXPathNewCompExpr:
438 *
439 * Create a new Xpath component
440 *
441 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
442 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000443static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000444xmlXPathNewCompExpr(void) {
445 xmlXPathCompExprPtr cur;
446
447 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
448 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000449 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000450 return(NULL);
451 }
452 memset(cur, 0, sizeof(xmlXPathCompExpr));
453 cur->maxStep = 10;
454 cur->nbStep = 0;
455 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
456 sizeof(xmlXPathStepOp));
457 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000458 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000459 xmlFree(cur);
460 return(NULL);
461 }
462 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
463 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000464#ifdef DEBUG_EVAL_COUNTS
465 cur->nb = 0;
466#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000467 return(cur);
468}
469
470/**
471 * xmlXPathFreeCompExpr:
472 * @comp: an XPATH comp
473 *
474 * Free up the memory allocated by @comp
475 */
476void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000477xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
478{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000479 xmlXPathStepOpPtr op;
480 int i;
481
482 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000483 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000484 if (comp->dict == NULL) {
485 for (i = 0; i < comp->nbStep; i++) {
486 op = &comp->steps[i];
487 if (op->value4 != NULL) {
488 if (op->op == XPATH_OP_VALUE)
489 xmlXPathFreeObject(op->value4);
490 else
491 xmlFree(op->value4);
492 }
493 if (op->value5 != NULL)
494 xmlFree(op->value5);
495 }
496 } else {
497 for (i = 0; i < comp->nbStep; i++) {
498 op = &comp->steps[i];
499 if (op->value4 != NULL) {
500 if (op->op == XPATH_OP_VALUE)
501 xmlXPathFreeObject(op->value4);
502 }
503 }
504 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000505 }
506 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000507 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000508 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000509#ifdef DEBUG_EVAL_COUNTS
510 if (comp->string != NULL) {
511 xmlFree(comp->string);
512 }
513#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000514 if (comp->expr != NULL) {
515 xmlFree(comp->expr);
516 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000517
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000518 xmlFree(comp);
519}
520
521/**
522 * xmlXPathCompExprAdd:
523 * @comp: the compiled expression
524 * @ch1: first child index
525 * @ch2: second child index
526 * @op: an op
527 * @value: the first int value
528 * @value2: the second int value
529 * @value3: the third int value
530 * @value4: the first string value
531 * @value5: the second string value
532 *
William M. Brack08171912003-12-29 02:52:11 +0000533 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000534 *
535 * Returns -1 in case of failure, the index otherwise
536 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000537static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000538xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
539 xmlXPathOp op, int value,
540 int value2, int value3, void *value4, void *value5) {
541 if (comp->nbStep >= comp->maxStep) {
542 xmlXPathStepOp *real;
543
544 comp->maxStep *= 2;
545 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
546 comp->maxStep * sizeof(xmlXPathStepOp));
547 if (real == NULL) {
548 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000549 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000550 return(-1);
551 }
552 comp->steps = real;
553 }
554 comp->last = comp->nbStep;
555 comp->steps[comp->nbStep].ch1 = ch1;
556 comp->steps[comp->nbStep].ch2 = ch2;
557 comp->steps[comp->nbStep].op = op;
558 comp->steps[comp->nbStep].value = value;
559 comp->steps[comp->nbStep].value2 = value2;
560 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000561 if ((comp->dict != NULL) &&
562 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
563 (op == XPATH_OP_COLLECT))) {
564 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000565 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000566 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000567 xmlFree(value4);
568 } else
569 comp->steps[comp->nbStep].value4 = NULL;
570 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000571 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000572 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000573 xmlFree(value5);
574 } else
575 comp->steps[comp->nbStep].value5 = NULL;
576 } else {
577 comp->steps[comp->nbStep].value4 = value4;
578 comp->steps[comp->nbStep].value5 = value5;
579 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000580 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000581 return(comp->nbStep++);
582}
583
Daniel Veillardf06307e2001-07-03 10:35:50 +0000584/**
585 * xmlXPathCompSwap:
586 * @comp: the compiled expression
587 * @op: operation index
588 *
589 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000590 */
591static void
592xmlXPathCompSwap(xmlXPathStepOpPtr op) {
593 int tmp;
594
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000595#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000596 /*
597 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000598 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000599 * application
600 */
601 if (xmlXPathDisableOptimizer)
602 return;
603#endif
604
Daniel Veillardf06307e2001-07-03 10:35:50 +0000605 tmp = op->ch1;
606 op->ch1 = op->ch2;
607 op->ch2 = tmp;
608}
609
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000610#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
611 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
612 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000613#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
614 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
615 (op), (val), (val2), (val3), (val4), (val5))
616
617#define PUSH_LEAVE_EXPR(op, val, val2) \
618xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
619
620#define PUSH_UNARY_EXPR(op, ch, val, val2) \
621xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
622
623#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000624xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
625 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000626
627/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000628 * *
629 * Debugging related functions *
630 * *
631 ************************************************************************/
632
Owen Taylor3473f882001-02-23 17:55:21 +0000633#define STRANGE \
634 xmlGenericError(xmlGenericErrorContext, \
635 "Internal error at %s:%d\n", \
636 __FILE__, __LINE__);
637
638#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000639static void
640xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000641 int i;
642 char shift[100];
643
644 for (i = 0;((i < depth) && (i < 25));i++)
645 shift[2 * i] = shift[2 * i + 1] = ' ';
646 shift[2 * i] = shift[2 * i + 1] = 0;
647 if (cur == NULL) {
648 fprintf(output, shift);
649 fprintf(output, "Node is NULL !\n");
650 return;
651
652 }
653
654 if ((cur->type == XML_DOCUMENT_NODE) ||
655 (cur->type == XML_HTML_DOCUMENT_NODE)) {
656 fprintf(output, shift);
657 fprintf(output, " /\n");
658 } else if (cur->type == XML_ATTRIBUTE_NODE)
659 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
660 else
661 xmlDebugDumpOneNode(output, cur, depth);
662}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000663static void
664xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000665 xmlNodePtr tmp;
666 int i;
667 char shift[100];
668
669 for (i = 0;((i < depth) && (i < 25));i++)
670 shift[2 * i] = shift[2 * i + 1] = ' ';
671 shift[2 * i] = shift[2 * i + 1] = 0;
672 if (cur == NULL) {
673 fprintf(output, shift);
674 fprintf(output, "Node is NULL !\n");
675 return;
676
677 }
678
679 while (cur != NULL) {
680 tmp = cur;
681 cur = cur->next;
682 xmlDebugDumpOneNode(output, tmp, depth);
683 }
684}
Owen Taylor3473f882001-02-23 17:55:21 +0000685
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000686static void
687xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000688 int i;
689 char shift[100];
690
691 for (i = 0;((i < depth) && (i < 25));i++)
692 shift[2 * i] = shift[2 * i + 1] = ' ';
693 shift[2 * i] = shift[2 * i + 1] = 0;
694
695 if (cur == NULL) {
696 fprintf(output, shift);
697 fprintf(output, "NodeSet is NULL !\n");
698 return;
699
700 }
701
Daniel Veillard911f49a2001-04-07 15:39:35 +0000702 if (cur != NULL) {
703 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
704 for (i = 0;i < cur->nodeNr;i++) {
705 fprintf(output, shift);
706 fprintf(output, "%d", i + 1);
707 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
708 }
Owen Taylor3473f882001-02-23 17:55:21 +0000709 }
710}
711
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000712static void
713xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000714 int i;
715 char shift[100];
716
717 for (i = 0;((i < depth) && (i < 25));i++)
718 shift[2 * i] = shift[2 * i + 1] = ' ';
719 shift[2 * i] = shift[2 * i + 1] = 0;
720
721 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
722 fprintf(output, shift);
723 fprintf(output, "Value Tree is NULL !\n");
724 return;
725
726 }
727
728 fprintf(output, shift);
729 fprintf(output, "%d", i + 1);
730 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
731}
Owen Taylor3473f882001-02-23 17:55:21 +0000732#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000733static void
734xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000735 int i;
736 char shift[100];
737
738 for (i = 0;((i < depth) && (i < 25));i++)
739 shift[2 * i] = shift[2 * i + 1] = ' ';
740 shift[2 * i] = shift[2 * i + 1] = 0;
741
742 if (cur == NULL) {
743 fprintf(output, shift);
744 fprintf(output, "LocationSet is NULL !\n");
745 return;
746
747 }
748
749 for (i = 0;i < cur->locNr;i++) {
750 fprintf(output, shift);
751 fprintf(output, "%d : ", i + 1);
752 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
753 }
754}
Daniel Veillard017b1082001-06-21 11:20:21 +0000755#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000756
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000757/**
758 * xmlXPathDebugDumpObject:
759 * @output: the FILE * to dump the output
760 * @cur: the object to inspect
761 * @depth: indentation level
762 *
763 * Dump the content of the object for debugging purposes
764 */
765void
766xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000767 int i;
768 char shift[100];
769
770 for (i = 0;((i < depth) && (i < 25));i++)
771 shift[2 * i] = shift[2 * i + 1] = ' ';
772 shift[2 * i] = shift[2 * i + 1] = 0;
773
774 fprintf(output, shift);
775
776 if (cur == NULL) {
777 fprintf(output, "Object is empty (NULL)\n");
778 return;
779 }
780 switch(cur->type) {
781 case XPATH_UNDEFINED:
782 fprintf(output, "Object is uninitialized\n");
783 break;
784 case XPATH_NODESET:
785 fprintf(output, "Object is a Node Set :\n");
786 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
787 break;
788 case XPATH_XSLT_TREE:
789 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000790 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000791 break;
792 case XPATH_BOOLEAN:
793 fprintf(output, "Object is a Boolean : ");
794 if (cur->boolval) fprintf(output, "true\n");
795 else fprintf(output, "false\n");
796 break;
797 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000798 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000799 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000800 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000801 break;
802 case -1:
803 fprintf(output, "Object is a number : -Infinity\n");
804 break;
805 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000806 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000807 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000808 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
809 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000810 } else {
811 fprintf(output, "Object is a number : %0g\n", cur->floatval);
812 }
813 }
Owen Taylor3473f882001-02-23 17:55:21 +0000814 break;
815 case XPATH_STRING:
816 fprintf(output, "Object is a string : ");
817 xmlDebugDumpString(output, cur->stringval);
818 fprintf(output, "\n");
819 break;
820 case XPATH_POINT:
821 fprintf(output, "Object is a point : index %d in node", cur->index);
822 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
823 fprintf(output, "\n");
824 break;
825 case XPATH_RANGE:
826 if ((cur->user2 == NULL) ||
827 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
828 fprintf(output, "Object is a collapsed range :\n");
829 fprintf(output, shift);
830 if (cur->index >= 0)
831 fprintf(output, "index %d in ", cur->index);
832 fprintf(output, "node\n");
833 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
834 depth + 1);
835 } else {
836 fprintf(output, "Object is a range :\n");
837 fprintf(output, shift);
838 fprintf(output, "From ");
839 if (cur->index >= 0)
840 fprintf(output, "index %d in ", cur->index);
841 fprintf(output, "node\n");
842 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
843 depth + 1);
844 fprintf(output, shift);
845 fprintf(output, "To ");
846 if (cur->index2 >= 0)
847 fprintf(output, "index %d in ", cur->index2);
848 fprintf(output, "node\n");
849 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
850 depth + 1);
851 fprintf(output, "\n");
852 }
853 break;
854 case XPATH_LOCATIONSET:
855#if defined(LIBXML_XPTR_ENABLED)
856 fprintf(output, "Object is a Location Set:\n");
857 xmlXPathDebugDumpLocationSet(output,
858 (xmlLocationSetPtr) cur->user, depth);
859#endif
860 break;
861 case XPATH_USERS:
862 fprintf(output, "Object is user defined\n");
863 break;
864 }
865}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000866
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000867static void
868xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000869 xmlXPathStepOpPtr op, int depth) {
870 int i;
871 char shift[100];
872
873 for (i = 0;((i < depth) && (i < 25));i++)
874 shift[2 * i] = shift[2 * i + 1] = ' ';
875 shift[2 * i] = shift[2 * i + 1] = 0;
876
877 fprintf(output, shift);
878 if (op == NULL) {
879 fprintf(output, "Step is NULL\n");
880 return;
881 }
882 switch (op->op) {
883 case XPATH_OP_END:
884 fprintf(output, "END"); break;
885 case XPATH_OP_AND:
886 fprintf(output, "AND"); break;
887 case XPATH_OP_OR:
888 fprintf(output, "OR"); break;
889 case XPATH_OP_EQUAL:
890 if (op->value)
891 fprintf(output, "EQUAL =");
892 else
893 fprintf(output, "EQUAL !=");
894 break;
895 case XPATH_OP_CMP:
896 if (op->value)
897 fprintf(output, "CMP <");
898 else
899 fprintf(output, "CMP >");
900 if (!op->value2)
901 fprintf(output, "=");
902 break;
903 case XPATH_OP_PLUS:
904 if (op->value == 0)
905 fprintf(output, "PLUS -");
906 else if (op->value == 1)
907 fprintf(output, "PLUS +");
908 else if (op->value == 2)
909 fprintf(output, "PLUS unary -");
910 else if (op->value == 3)
911 fprintf(output, "PLUS unary - -");
912 break;
913 case XPATH_OP_MULT:
914 if (op->value == 0)
915 fprintf(output, "MULT *");
916 else if (op->value == 1)
917 fprintf(output, "MULT div");
918 else
919 fprintf(output, "MULT mod");
920 break;
921 case XPATH_OP_UNION:
922 fprintf(output, "UNION"); break;
923 case XPATH_OP_ROOT:
924 fprintf(output, "ROOT"); break;
925 case XPATH_OP_NODE:
926 fprintf(output, "NODE"); break;
927 case XPATH_OP_RESET:
928 fprintf(output, "RESET"); break;
929 case XPATH_OP_SORT:
930 fprintf(output, "SORT"); break;
931 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000932 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
933 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
934 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000935 const xmlChar *prefix = op->value4;
936 const xmlChar *name = op->value5;
937
938 fprintf(output, "COLLECT ");
939 switch (axis) {
940 case AXIS_ANCESTOR:
941 fprintf(output, " 'ancestors' "); break;
942 case AXIS_ANCESTOR_OR_SELF:
943 fprintf(output, " 'ancestors-or-self' "); break;
944 case AXIS_ATTRIBUTE:
945 fprintf(output, " 'attributes' "); break;
946 case AXIS_CHILD:
947 fprintf(output, " 'child' "); break;
948 case AXIS_DESCENDANT:
949 fprintf(output, " 'descendant' "); break;
950 case AXIS_DESCENDANT_OR_SELF:
951 fprintf(output, " 'descendant-or-self' "); break;
952 case AXIS_FOLLOWING:
953 fprintf(output, " 'following' "); break;
954 case AXIS_FOLLOWING_SIBLING:
955 fprintf(output, " 'following-siblings' "); break;
956 case AXIS_NAMESPACE:
957 fprintf(output, " 'namespace' "); break;
958 case AXIS_PARENT:
959 fprintf(output, " 'parent' "); break;
960 case AXIS_PRECEDING:
961 fprintf(output, " 'preceding' "); break;
962 case AXIS_PRECEDING_SIBLING:
963 fprintf(output, " 'preceding-sibling' "); break;
964 case AXIS_SELF:
965 fprintf(output, " 'self' "); break;
966 }
967 switch (test) {
968 case NODE_TEST_NONE:
969 fprintf(output, "'none' "); break;
970 case NODE_TEST_TYPE:
971 fprintf(output, "'type' "); break;
972 case NODE_TEST_PI:
973 fprintf(output, "'PI' "); break;
974 case NODE_TEST_ALL:
975 fprintf(output, "'all' "); break;
976 case NODE_TEST_NS:
977 fprintf(output, "'namespace' "); break;
978 case NODE_TEST_NAME:
979 fprintf(output, "'name' "); break;
980 }
981 switch (type) {
982 case NODE_TYPE_NODE:
983 fprintf(output, "'node' "); break;
984 case NODE_TYPE_COMMENT:
985 fprintf(output, "'comment' "); break;
986 case NODE_TYPE_TEXT:
987 fprintf(output, "'text' "); break;
988 case NODE_TYPE_PI:
989 fprintf(output, "'PI' "); break;
990 }
991 if (prefix != NULL)
992 fprintf(output, "%s:", prefix);
993 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +0000994 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000995 break;
996
997 }
998 case XPATH_OP_VALUE: {
999 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1000
1001 fprintf(output, "ELEM ");
1002 xmlXPathDebugDumpObject(output, object, 0);
1003 goto finish;
1004 }
1005 case XPATH_OP_VARIABLE: {
1006 const xmlChar *prefix = op->value5;
1007 const xmlChar *name = op->value4;
1008
1009 if (prefix != NULL)
1010 fprintf(output, "VARIABLE %s:%s", prefix, name);
1011 else
1012 fprintf(output, "VARIABLE %s", name);
1013 break;
1014 }
1015 case XPATH_OP_FUNCTION: {
1016 int nbargs = op->value;
1017 const xmlChar *prefix = op->value5;
1018 const xmlChar *name = op->value4;
1019
1020 if (prefix != NULL)
1021 fprintf(output, "FUNCTION %s:%s(%d args)",
1022 prefix, name, nbargs);
1023 else
1024 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1025 break;
1026 }
1027 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1028 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001029 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001030#ifdef LIBXML_XPTR_ENABLED
1031 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1032#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001033 default:
1034 fprintf(output, "UNKNOWN %d\n", op->op); return;
1035 }
1036 fprintf(output, "\n");
1037finish:
1038 if (op->ch1 >= 0)
1039 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1040 if (op->ch2 >= 0)
1041 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1042}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001043
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001044/**
1045 * xmlXPathDebugDumpCompExpr:
1046 * @output: the FILE * for the output
1047 * @comp: the precompiled XPath expression
1048 * @depth: the indentation level.
1049 *
1050 * Dumps the tree of the compiled XPath expression.
1051 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001052void
1053xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1054 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001055 int i;
1056 char shift[100];
1057
1058 for (i = 0;((i < depth) && (i < 25));i++)
1059 shift[2 * i] = shift[2 * i + 1] = ' ';
1060 shift[2 * i] = shift[2 * i + 1] = 0;
1061
1062 fprintf(output, shift);
1063
1064 if (comp == NULL) {
1065 fprintf(output, "Compiled Expression is NULL\n");
1066 return;
1067 }
1068 fprintf(output, "Compiled Expression : %d elements\n",
1069 comp->nbStep);
1070 i = comp->last;
1071 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1072}
Daniel Veillard017b1082001-06-21 11:20:21 +00001073#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001074
1075/************************************************************************
1076 * *
1077 * Parser stacks related functions and macros *
1078 * *
1079 ************************************************************************/
1080
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001081/**
1082 * valuePop:
1083 * @ctxt: an XPath evaluation context
1084 *
1085 * Pops the top XPath object from the value stack
1086 *
1087 * Returns the XPath object just removed
1088 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001089extern xmlXPathObjectPtr
1090valuePop(xmlXPathParserContextPtr ctxt)
1091{
1092 xmlXPathObjectPtr ret;
1093
1094 if (ctxt->valueNr <= 0)
1095 return (0);
1096 ctxt->valueNr--;
1097 if (ctxt->valueNr > 0)
1098 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1099 else
1100 ctxt->value = NULL;
1101 ret = ctxt->valueTab[ctxt->valueNr];
1102 ctxt->valueTab[ctxt->valueNr] = 0;
1103 return (ret);
1104}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001105/**
1106 * valuePush:
1107 * @ctxt: an XPath evaluation context
1108 * @value: the XPath object
1109 *
1110 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001111 *
1112 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001113 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001114extern int
1115valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1116{
1117 if (ctxt->valueNr >= ctxt->valueMax) {
1118 ctxt->valueMax *= 2;
1119 ctxt->valueTab =
1120 (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1121 ctxt->valueMax *
1122 sizeof(ctxt->valueTab[0]));
1123 if (ctxt->valueTab == NULL) {
1124 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1125 return (0);
1126 }
1127 }
1128 ctxt->valueTab[ctxt->valueNr] = value;
1129 ctxt->value = value;
1130 return (ctxt->valueNr++);
1131}
Owen Taylor3473f882001-02-23 17:55:21 +00001132
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001133/**
1134 * xmlXPathPopBoolean:
1135 * @ctxt: an XPath parser context
1136 *
1137 * Pops a boolean from the stack, handling conversion if needed.
1138 * Check error with #xmlXPathCheckError.
1139 *
1140 * Returns the boolean
1141 */
1142int
1143xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1144 xmlXPathObjectPtr obj;
1145 int ret;
1146
1147 obj = valuePop(ctxt);
1148 if (obj == NULL) {
1149 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1150 return(0);
1151 }
William M. Brack08171912003-12-29 02:52:11 +00001152 if (obj->type != XPATH_BOOLEAN)
1153 ret = xmlXPathCastToBoolean(obj);
1154 else
1155 ret = obj->boolval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001156 xmlXPathFreeObject(obj);
1157 return(ret);
1158}
1159
1160/**
1161 * xmlXPathPopNumber:
1162 * @ctxt: an XPath parser context
1163 *
1164 * Pops a number from the stack, handling conversion if needed.
1165 * Check error with #xmlXPathCheckError.
1166 *
1167 * Returns the number
1168 */
1169double
1170xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1171 xmlXPathObjectPtr obj;
1172 double ret;
1173
1174 obj = valuePop(ctxt);
1175 if (obj == NULL) {
1176 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1177 return(0);
1178 }
William M. Brack08171912003-12-29 02:52:11 +00001179 if (obj->type != XPATH_NUMBER)
1180 ret = xmlXPathCastToNumber(obj);
1181 else
1182 ret = obj->floatval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001183 xmlXPathFreeObject(obj);
1184 return(ret);
1185}
1186
1187/**
1188 * xmlXPathPopString:
1189 * @ctxt: an XPath parser context
1190 *
1191 * Pops a string from the stack, handling conversion if needed.
1192 * Check error with #xmlXPathCheckError.
1193 *
1194 * Returns the string
1195 */
1196xmlChar *
1197xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1198 xmlXPathObjectPtr obj;
1199 xmlChar * ret;
1200
1201 obj = valuePop(ctxt);
1202 if (obj == NULL) {
1203 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1204 return(NULL);
1205 }
William M. Brack08171912003-12-29 02:52:11 +00001206 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001207 /* TODO: needs refactoring somewhere else */
1208 if (obj->stringval == ret)
1209 obj->stringval = NULL;
1210 xmlXPathFreeObject(obj);
1211 return(ret);
1212}
1213
1214/**
1215 * xmlXPathPopNodeSet:
1216 * @ctxt: an XPath parser context
1217 *
1218 * Pops a node-set from the stack, handling conversion if needed.
1219 * Check error with #xmlXPathCheckError.
1220 *
1221 * Returns the node-set
1222 */
1223xmlNodeSetPtr
1224xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1225 xmlXPathObjectPtr obj;
1226 xmlNodeSetPtr ret;
1227
1228 if (ctxt->value == NULL) {
1229 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1230 return(NULL);
1231 }
1232 if (!xmlXPathStackIsNodeSet(ctxt)) {
1233 xmlXPathSetTypeError(ctxt);
1234 return(NULL);
1235 }
1236 obj = valuePop(ctxt);
1237 ret = obj->nodesetval;
Daniel Veillard9deb2422003-07-28 20:40:59 +00001238 /* to fix memory leak of not clearing obj->user */
1239 if (obj->boolval && obj->user != NULL)
1240 xmlFreeNodeList((xmlNodePtr) obj->user);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001241 xmlXPathFreeNodeSetList(obj);
1242 return(ret);
1243}
1244
1245/**
1246 * xmlXPathPopExternal:
1247 * @ctxt: an XPath parser context
1248 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001249 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001250 * Check error with #xmlXPathCheckError.
1251 *
1252 * Returns the object
1253 */
1254void *
1255xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1256 xmlXPathObjectPtr obj;
1257 void * ret;
1258
1259 if (ctxt->value == NULL) {
1260 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1261 return(NULL);
1262 }
1263 if (ctxt->value->type != XPATH_USERS) {
1264 xmlXPathSetTypeError(ctxt);
1265 return(NULL);
1266 }
1267 obj = valuePop(ctxt);
1268 ret = obj->user;
1269 xmlXPathFreeObject(obj);
1270 return(ret);
1271}
1272
Owen Taylor3473f882001-02-23 17:55:21 +00001273/*
1274 * Macros for accessing the content. Those should be used only by the parser,
1275 * and not exported.
1276 *
1277 * Dirty macros, i.e. one need to make assumption on the context to use them
1278 *
1279 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1280 * CUR returns the current xmlChar value, i.e. a 8 bit value
1281 * in ISO-Latin or UTF-8.
1282 * This should be used internally by the parser
1283 * only to compare to ASCII values otherwise it would break when
1284 * running with UTF-8 encoding.
1285 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1286 * to compare on ASCII based substring.
1287 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1288 * strings within the parser.
1289 * CURRENT Returns the current char value, with the full decoding of
1290 * UTF-8 if we are using this mode. It returns an int.
1291 * NEXT Skip to the next character, this does the proper decoding
1292 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1293 * It returns the pointer to the current xmlChar.
1294 */
1295
1296#define CUR (*ctxt->cur)
1297#define SKIP(val) ctxt->cur += (val)
1298#define NXT(val) ctxt->cur[(val)]
1299#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001300#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1301
1302#define COPY_BUF(l,b,i,v) \
1303 if (l == 1) b[i++] = (xmlChar) v; \
1304 else i += xmlCopyChar(l,&b[i],v)
1305
1306#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001307
1308#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001309 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001310
1311#define CURRENT (*ctxt->cur)
1312#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1313
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001314
1315#ifndef DBL_DIG
1316#define DBL_DIG 16
1317#endif
1318#ifndef DBL_EPSILON
1319#define DBL_EPSILON 1E-9
1320#endif
1321
1322#define UPPER_DOUBLE 1E9
1323#define LOWER_DOUBLE 1E-5
1324
1325#define INTEGER_DIGITS DBL_DIG
1326#define FRACTION_DIGITS (DBL_DIG + 1)
1327#define EXPONENT_DIGITS (3 + 2)
1328
1329/**
1330 * xmlXPathFormatNumber:
1331 * @number: number to format
1332 * @buffer: output buffer
1333 * @buffersize: size of output buffer
1334 *
1335 * Convert the number into a string representation.
1336 */
1337static void
1338xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1339{
Daniel Veillardcda96922001-08-21 10:56:31 +00001340 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001341 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001342 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001343 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001344 break;
1345 case -1:
1346 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001347 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001348 break;
1349 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001350 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001351 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001352 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001353 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001354 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001355 } else if (number == ((int) number)) {
1356 char work[30];
1357 char *ptr, *cur;
1358 int res, value = (int) number;
1359
1360 ptr = &buffer[0];
1361 if (value < 0) {
1362 *ptr++ = '-';
1363 value = -value;
1364 }
1365 if (value == 0) {
1366 *ptr++ = '0';
1367 } else {
1368 cur = &work[0];
1369 while (value != 0) {
1370 res = value % 10;
1371 value = value / 10;
1372 *cur++ = '0' + res;
1373 }
1374 cur--;
1375 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1376 *ptr++ = *cur--;
1377 }
1378 }
1379 if (ptr - buffer < buffersize) {
1380 *ptr = 0;
1381 } else if (buffersize > 0) {
1382 ptr--;
1383 *ptr = 0;
1384 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001385 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001386 /* 3 is sign, decimal point, and terminating zero */
1387 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1388 int integer_place, fraction_place;
1389 char *ptr;
1390 char *after_fraction;
1391 double absolute_value;
1392 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001393
Bjorn Reese70a9da52001-04-21 16:57:29 +00001394 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001395
Bjorn Reese70a9da52001-04-21 16:57:29 +00001396 /*
1397 * First choose format - scientific or regular floating point.
1398 * In either case, result is in work, and after_fraction points
1399 * just past the fractional part.
1400 */
1401 if ( ((absolute_value > UPPER_DOUBLE) ||
1402 (absolute_value < LOWER_DOUBLE)) &&
1403 (absolute_value != 0.0) ) {
1404 /* Use scientific notation */
1405 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1406 fraction_place = DBL_DIG - 1;
1407 snprintf(work, sizeof(work),"%*.*e",
1408 integer_place, fraction_place, number);
1409 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001410 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001411 else {
1412 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001413 if (absolute_value > 0.0)
1414 integer_place = 1 + (int)log10(absolute_value);
1415 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001416 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001417 fraction_place = (integer_place > 0)
1418 ? DBL_DIG - integer_place
1419 : DBL_DIG;
1420 size = snprintf(work, sizeof(work), "%0.*f",
1421 fraction_place, number);
1422 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001423 }
1424
Bjorn Reese70a9da52001-04-21 16:57:29 +00001425 /* Remove fractional trailing zeroes */
1426 ptr = after_fraction;
1427 while (*(--ptr) == '0')
1428 ;
1429 if (*ptr != '.')
1430 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001431 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001432
1433 /* Finally copy result back to caller */
1434 size = strlen(work) + 1;
1435 if (size > buffersize) {
1436 work[buffersize - 1] = 0;
1437 size = buffersize;
1438 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001439 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001440 }
1441 break;
1442 }
1443}
1444
Owen Taylor3473f882001-02-23 17:55:21 +00001445
1446/************************************************************************
1447 * *
1448 * Routines to handle NodeSets *
1449 * *
1450 ************************************************************************/
1451
1452/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001453 * xmlXPathOrderDocElems:
1454 * @doc: an input document
1455 *
1456 * Call this routine to speed up XPath computation on static documents.
1457 * This stamps all the element nodes with the document order
1458 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00001459 * field, the value stored is actually - the node number (starting at -1)
1460 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001461 *
William M. Brack08171912003-12-29 02:52:11 +00001462 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001463 * of error.
1464 */
1465long
1466xmlXPathOrderDocElems(xmlDocPtr doc) {
1467 long count = 0;
1468 xmlNodePtr cur;
1469
1470 if (doc == NULL)
1471 return(-1);
1472 cur = doc->children;
1473 while (cur != NULL) {
1474 if (cur->type == XML_ELEMENT_NODE) {
1475 cur->content = (void *) (-(++count));
1476 if (cur->children != NULL) {
1477 cur = cur->children;
1478 continue;
1479 }
1480 }
1481 if (cur->next != NULL) {
1482 cur = cur->next;
1483 continue;
1484 }
1485 do {
1486 cur = cur->parent;
1487 if (cur == NULL)
1488 break;
1489 if (cur == (xmlNodePtr) doc) {
1490 cur = NULL;
1491 break;
1492 }
1493 if (cur->next != NULL) {
1494 cur = cur->next;
1495 break;
1496 }
1497 } while (cur != NULL);
1498 }
1499 return(count);
1500}
1501
1502/**
Owen Taylor3473f882001-02-23 17:55:21 +00001503 * xmlXPathCmpNodes:
1504 * @node1: the first node
1505 * @node2: the second node
1506 *
1507 * Compare two nodes w.r.t document order
1508 *
1509 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00001510 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001511 */
1512int
1513xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1514 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001515 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001516 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001517 xmlNodePtr cur, root;
1518
1519 if ((node1 == NULL) || (node2 == NULL))
1520 return(-2);
1521 /*
1522 * a couple of optimizations which will avoid computations in most cases
1523 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001524 if (node1->type == XML_ATTRIBUTE_NODE) {
1525 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001526 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001527 node1 = node1->parent;
1528 }
1529 if (node2->type == XML_ATTRIBUTE_NODE) {
1530 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001531 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001532 node2 = node2->parent;
1533 }
1534 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001535 if (attr1 == attr2) {
1536 /* not required, but we keep attributes in order */
1537 if (attr1 != 0) {
1538 cur = attrNode2->prev;
1539 while (cur != NULL) {
1540 if (cur == attrNode1)
1541 return (1);
1542 cur = cur->prev;
1543 }
1544 return (-1);
1545 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001546 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001547 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001548 if (attr2 == 1)
1549 return(1);
1550 return(-1);
1551 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001552 if ((node1->type == XML_NAMESPACE_DECL) ||
1553 (node2->type == XML_NAMESPACE_DECL))
1554 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001555 if (node1 == node2->prev)
1556 return(1);
1557 if (node1 == node2->next)
1558 return(-1);
1559
1560 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001561 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001562 */
1563 if ((node1->type == XML_ELEMENT_NODE) &&
1564 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001565 (0 > (long) node1->content) &&
1566 (0 > (long) node2->content) &&
1567 (node1->doc == node2->doc)) {
1568 long l1, l2;
1569
1570 l1 = -((long) node1->content);
1571 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001572 if (l1 < l2)
1573 return(1);
1574 if (l1 > l2)
1575 return(-1);
1576 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001577
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001578 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001579 * compute depth to root
1580 */
1581 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1582 if (cur == node1)
1583 return(1);
1584 depth2++;
1585 }
1586 root = cur;
1587 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1588 if (cur == node2)
1589 return(-1);
1590 depth1++;
1591 }
1592 /*
1593 * Distinct document (or distinct entities :-( ) case.
1594 */
1595 if (root != cur) {
1596 return(-2);
1597 }
1598 /*
1599 * get the nearest common ancestor.
1600 */
1601 while (depth1 > depth2) {
1602 depth1--;
1603 node1 = node1->parent;
1604 }
1605 while (depth2 > depth1) {
1606 depth2--;
1607 node2 = node2->parent;
1608 }
1609 while (node1->parent != node2->parent) {
1610 node1 = node1->parent;
1611 node2 = node2->parent;
1612 /* should not happen but just in case ... */
1613 if ((node1 == NULL) || (node2 == NULL))
1614 return(-2);
1615 }
1616 /*
1617 * Find who's first.
1618 */
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
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008798#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008799eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008800#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008801 op1 = ctxt->comp->last;
8802 ctxt->comp->last = -1;
8803
Owen Taylor3473f882001-02-23 17:55:21 +00008804 SKIP_BLANKS;
8805 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008806 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008807 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008808
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008809#ifdef LIBXML_XPTR_ENABLED
8810 if (rangeto) {
8811 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8812 } else
8813#endif
8814 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8815 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008816
Owen Taylor3473f882001-02-23 17:55:21 +00008817 }
8818#ifdef DEBUG_STEP
8819 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008820 if (ctxt->value == NULL)
8821 xmlGenericError(xmlGenericErrorContext, "no value\n");
8822 else if (ctxt->value->nodesetval == NULL)
8823 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8824 else
8825 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8826 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008827#endif
8828}
8829
8830/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008831 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008832 * @ctxt: the XPath Parser context
8833 *
8834 * [3] RelativeLocationPath ::= Step
8835 * | RelativeLocationPath '/' Step
8836 * | AbbreviatedRelativeLocationPath
8837 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8838 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008839 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008840 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008841static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008842xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008843(xmlXPathParserContextPtr ctxt) {
8844 SKIP_BLANKS;
8845 if ((CUR == '/') && (NXT(1) == '/')) {
8846 SKIP(2);
8847 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008848 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8849 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008850 } else if (CUR == '/') {
8851 NEXT;
8852 SKIP_BLANKS;
8853 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008854 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008855 SKIP_BLANKS;
8856 while (CUR == '/') {
8857 if ((CUR == '/') && (NXT(1) == '/')) {
8858 SKIP(2);
8859 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008860 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008861 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008862 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008863 } else if (CUR == '/') {
8864 NEXT;
8865 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008866 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008867 }
8868 SKIP_BLANKS;
8869 }
8870}
8871
8872/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008873 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008874 * @ctxt: the XPath Parser context
8875 *
8876 * [1] LocationPath ::= RelativeLocationPath
8877 * | AbsoluteLocationPath
8878 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8879 * | AbbreviatedAbsoluteLocationPath
8880 * [10] AbbreviatedAbsoluteLocationPath ::=
8881 * '//' RelativeLocationPath
8882 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008883 * Compile a location path
8884 *
Owen Taylor3473f882001-02-23 17:55:21 +00008885 * // is short for /descendant-or-self::node()/. For example,
8886 * //para is short for /descendant-or-self::node()/child::para and
8887 * so will select any para element in the document (even a para element
8888 * that is a document element will be selected by //para since the
8889 * document element node is a child of the root node); div//para is
8890 * short for div/descendant-or-self::node()/child::para and so will
8891 * select all para descendants of div children.
8892 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008893static void
8894xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008895 SKIP_BLANKS;
8896 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008897 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008898 } else {
8899 while (CUR == '/') {
8900 if ((CUR == '/') && (NXT(1) == '/')) {
8901 SKIP(2);
8902 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008903 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8904 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008905 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008906 } else if (CUR == '/') {
8907 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008908 SKIP_BLANKS;
8909 if ((CUR != 0 ) &&
William M. Brack76e95df2003-10-18 16:20:14 +00008910 ((IS_LETTER_CH(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00008911 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008912 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008913 }
8914 }
8915 }
8916}
8917
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008918/************************************************************************
8919 * *
8920 * XPath precompiled expression evaluation *
8921 * *
8922 ************************************************************************/
8923
Daniel Veillardf06307e2001-07-03 10:35:50 +00008924static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008925xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8926
8927/**
8928 * xmlXPathNodeCollectAndTest:
8929 * @ctxt: the XPath Parser context
8930 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008931 * @first: pointer to the first element in document order
8932 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008933 *
8934 * This is the function implementing a step: based on the current list
8935 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00008936 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008937 *
8938 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008939 *
William M. Brack08171912003-12-29 02:52:11 +00008940 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008941 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008942static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008943xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008944 xmlXPathStepOpPtr op,
8945 xmlNodePtr * first, xmlNodePtr * last)
8946{
William M. Brack78637da2003-07-31 14:47:38 +00008947 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
8948 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
8949 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008950 const xmlChar *prefix = op->value4;
8951 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008952 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008953
8954#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008955 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008956#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008957 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008958 xmlNodeSetPtr ret, list;
8959 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008960 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008961 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008962 xmlNodePtr cur = NULL;
8963 xmlXPathObjectPtr obj;
8964 xmlNodeSetPtr nodelist;
8965 xmlNodePtr tmp;
8966
Daniel Veillardf06307e2001-07-03 10:35:50 +00008967 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008968 obj = valuePop(ctxt);
8969 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008970 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008971 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008972 URI = xmlXPathNsLookup(ctxt->context, prefix);
8973 if (URI == NULL)
8974 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008975 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008976#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008977 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008978#endif
8979 switch (axis) {
8980 case AXIS_ANCESTOR:
8981#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008982 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008983#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008984 first = NULL;
8985 next = xmlXPathNextAncestor;
8986 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008987 case AXIS_ANCESTOR_OR_SELF:
8988#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008989 xmlGenericError(xmlGenericErrorContext,
8990 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008991#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008992 first = NULL;
8993 next = xmlXPathNextAncestorOrSelf;
8994 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008995 case AXIS_ATTRIBUTE:
8996#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008997 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008998#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008999 first = NULL;
9000 last = NULL;
9001 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009002 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009003 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009004 case AXIS_CHILD:
9005#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009006 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009007#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009008 last = NULL;
9009 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009010 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009011 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009012 case AXIS_DESCENDANT:
9013#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009014 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009015#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009016 last = NULL;
9017 next = xmlXPathNextDescendant;
9018 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009019 case AXIS_DESCENDANT_OR_SELF:
9020#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009021 xmlGenericError(xmlGenericErrorContext,
9022 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009023#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009024 last = NULL;
9025 next = xmlXPathNextDescendantOrSelf;
9026 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009027 case AXIS_FOLLOWING:
9028#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009029 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009030#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009031 last = NULL;
9032 next = xmlXPathNextFollowing;
9033 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009034 case AXIS_FOLLOWING_SIBLING:
9035#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009036 xmlGenericError(xmlGenericErrorContext,
9037 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009038#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009039 last = NULL;
9040 next = xmlXPathNextFollowingSibling;
9041 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009042 case AXIS_NAMESPACE:
9043#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009044 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009045#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009046 first = NULL;
9047 last = NULL;
9048 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009049 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009050 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009051 case AXIS_PARENT:
9052#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009053 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009054#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009055 first = NULL;
9056 next = xmlXPathNextParent;
9057 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009058 case AXIS_PRECEDING:
9059#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009060 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009061#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009062 first = NULL;
9063 next = xmlXPathNextPrecedingInternal;
9064 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009065 case AXIS_PRECEDING_SIBLING:
9066#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009067 xmlGenericError(xmlGenericErrorContext,
9068 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009069#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009070 first = NULL;
9071 next = xmlXPathNextPrecedingSibling;
9072 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009073 case AXIS_SELF:
9074#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009075 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009076#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009077 first = NULL;
9078 last = NULL;
9079 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009080 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009081 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009082 }
9083 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009084 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009085
9086 nodelist = obj->nodesetval;
9087 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009088 xmlXPathFreeObject(obj);
9089 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9090 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009091 }
9092 addNode = xmlXPathNodeSetAddUnique;
9093 ret = NULL;
9094#ifdef DEBUG_STEP
9095 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009096 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009097 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009098 case NODE_TEST_NONE:
9099 xmlGenericError(xmlGenericErrorContext,
9100 " searching for none !!!\n");
9101 break;
9102 case NODE_TEST_TYPE:
9103 xmlGenericError(xmlGenericErrorContext,
9104 " searching for type %d\n", type);
9105 break;
9106 case NODE_TEST_PI:
9107 xmlGenericError(xmlGenericErrorContext,
9108 " searching for PI !!!\n");
9109 break;
9110 case NODE_TEST_ALL:
9111 xmlGenericError(xmlGenericErrorContext,
9112 " searching for *\n");
9113 break;
9114 case NODE_TEST_NS:
9115 xmlGenericError(xmlGenericErrorContext,
9116 " searching for namespace %s\n",
9117 prefix);
9118 break;
9119 case NODE_TEST_NAME:
9120 xmlGenericError(xmlGenericErrorContext,
9121 " searching for name %s\n", name);
9122 if (prefix != NULL)
9123 xmlGenericError(xmlGenericErrorContext,
9124 " with namespace %s\n", prefix);
9125 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009126 }
9127 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9128#endif
9129 /*
9130 * 2.3 Node Tests
9131 * - For the attribute axis, the principal node type is attribute.
9132 * - For the namespace axis, the principal node type is namespace.
9133 * - For other axes, the principal node type is element.
9134 *
9135 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009136 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009137 * select all element children of the context node
9138 */
9139 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009140 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009141 ctxt->context->node = nodelist->nodeTab[i];
9142
Daniel Veillardf06307e2001-07-03 10:35:50 +00009143 cur = NULL;
9144 list = xmlXPathNodeSetCreate(NULL);
9145 do {
9146 cur = next(ctxt, cur);
9147 if (cur == NULL)
9148 break;
9149 if ((first != NULL) && (*first == cur))
9150 break;
9151 if (((t % 256) == 0) &&
9152 (first != NULL) && (*first != NULL) &&
9153 (xmlXPathCmpNodes(*first, cur) >= 0))
9154 break;
9155 if ((last != NULL) && (*last == cur))
9156 break;
9157 if (((t % 256) == 0) &&
9158 (last != NULL) && (*last != NULL) &&
9159 (xmlXPathCmpNodes(cur, *last) >= 0))
9160 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009161 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009162#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009163 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9164#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009165 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009166 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009167 ctxt->context->node = tmp;
9168 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009169 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009170 if ((cur->type == type) ||
9171 ((type == NODE_TYPE_NODE) &&
9172 ((cur->type == XML_DOCUMENT_NODE) ||
9173 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9174 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009175 (cur->type == XML_NAMESPACE_DECL) ||
9176 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009177 (cur->type == XML_PI_NODE) ||
9178 (cur->type == XML_COMMENT_NODE) ||
9179 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009180 (cur->type == XML_TEXT_NODE))) ||
9181 ((type == NODE_TYPE_TEXT) &&
9182 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009183#ifdef DEBUG_STEP
9184 n++;
9185#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009186 addNode(list, cur);
9187 }
9188 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009189 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009190 if (cur->type == XML_PI_NODE) {
9191 if ((name != NULL) &&
9192 (!xmlStrEqual(name, cur->name)))
9193 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009194#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009195 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009196#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009197 addNode(list, cur);
9198 }
9199 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009200 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009201 if (axis == AXIS_ATTRIBUTE) {
9202 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009203#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009204 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009205#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009206 addNode(list, cur);
9207 }
9208 } else if (axis == AXIS_NAMESPACE) {
9209 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009210#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009211 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009212#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009213 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9214 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009215 }
9216 } else {
9217 if (cur->type == XML_ELEMENT_NODE) {
9218 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009219#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009220 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009221#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009222 addNode(list, cur);
9223 } else if ((cur->ns != NULL) &&
9224 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009225#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009226 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009227#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009228 addNode(list, cur);
9229 }
9230 }
9231 }
9232 break;
9233 case NODE_TEST_NS:{
9234 TODO;
9235 break;
9236 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009237 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009238 switch (cur->type) {
9239 case XML_ELEMENT_NODE:
9240 if (xmlStrEqual(name, cur->name)) {
9241 if (prefix == NULL) {
9242 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009243#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009244 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009245#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009246 addNode(list, cur);
9247 }
9248 } else {
9249 if ((cur->ns != NULL) &&
9250 (xmlStrEqual(URI,
9251 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009252#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009253 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009254#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009255 addNode(list, cur);
9256 }
9257 }
9258 }
9259 break;
9260 case XML_ATTRIBUTE_NODE:{
9261 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009262
Daniel Veillardf06307e2001-07-03 10:35:50 +00009263 if (xmlStrEqual(name, attr->name)) {
9264 if (prefix == NULL) {
9265 if ((attr->ns == NULL) ||
9266 (attr->ns->prefix == NULL)) {
9267#ifdef DEBUG_STEP
9268 n++;
9269#endif
9270 addNode(list,
9271 (xmlNodePtr) attr);
9272 }
9273 } else {
9274 if ((attr->ns != NULL) &&
9275 (xmlStrEqual(URI,
9276 attr->ns->
9277 href))) {
9278#ifdef DEBUG_STEP
9279 n++;
9280#endif
9281 addNode(list,
9282 (xmlNodePtr) attr);
9283 }
9284 }
9285 }
9286 break;
9287 }
9288 case XML_NAMESPACE_DECL:
9289 if (cur->type == XML_NAMESPACE_DECL) {
9290 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009291
Daniel Veillardf06307e2001-07-03 10:35:50 +00009292 if ((ns->prefix != NULL) && (name != NULL)
9293 && (xmlStrEqual(ns->prefix, name))) {
9294#ifdef DEBUG_STEP
9295 n++;
9296#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009297 xmlXPathNodeSetAddNs(list,
9298 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009299 }
9300 }
9301 break;
9302 default:
9303 break;
9304 }
9305 break;
9306 break;
9307 }
9308 } while (cur != NULL);
9309
9310 /*
9311 * If there is some predicate filtering do it now
9312 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009313 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009314 xmlXPathObjectPtr obj2;
9315
9316 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9317 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9318 CHECK_TYPE0(XPATH_NODESET);
9319 obj2 = valuePop(ctxt);
9320 list = obj2->nodesetval;
9321 obj2->nodesetval = NULL;
9322 xmlXPathFreeObject(obj2);
9323 }
9324 if (ret == NULL) {
9325 ret = list;
9326 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009327 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009328 xmlXPathFreeNodeSet(list);
9329 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009330 }
9331 ctxt->context->node = tmp;
9332#ifdef DEBUG_STEP
9333 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009334 "\nExamined %d nodes, found %d nodes at that step\n",
9335 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009336#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009337 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009338 if ((obj->boolval) && (obj->user != NULL)) {
9339 ctxt->value->boolval = 1;
9340 ctxt->value->user = obj->user;
9341 obj->user = NULL;
9342 obj->boolval = 0;
9343 }
9344 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009345 return(t);
9346}
9347
9348/**
9349 * xmlXPathNodeCollectAndTestNth:
9350 * @ctxt: the XPath Parser context
9351 * @op: the XPath precompiled step operation
9352 * @indx: the index to collect
9353 * @first: pointer to the first element in document order
9354 * @last: pointer to the last element in document order
9355 *
9356 * This is the function implementing a step: based on the current list
9357 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009358 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009359 *
9360 * Pushes the new NodeSet resulting from the search.
9361 * Returns the number of node traversed
9362 */
9363static int
9364xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9365 xmlXPathStepOpPtr op, int indx,
9366 xmlNodePtr * first, xmlNodePtr * last)
9367{
William M. Brack78637da2003-07-31 14:47:38 +00009368 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9369 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9370 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009371 const xmlChar *prefix = op->value4;
9372 const xmlChar *name = op->value5;
9373 const xmlChar *URI = NULL;
9374 int n = 0, t = 0;
9375
9376 int i;
9377 xmlNodeSetPtr list;
9378 xmlXPathTraversalFunction next = NULL;
9379 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9380 xmlNodePtr cur = NULL;
9381 xmlXPathObjectPtr obj;
9382 xmlNodeSetPtr nodelist;
9383 xmlNodePtr tmp;
9384
9385 CHECK_TYPE0(XPATH_NODESET);
9386 obj = valuePop(ctxt);
9387 addNode = xmlXPathNodeSetAdd;
9388 if (prefix != NULL) {
9389 URI = xmlXPathNsLookup(ctxt->context, prefix);
9390 if (URI == NULL)
9391 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9392 }
9393#ifdef DEBUG_STEP_NTH
9394 xmlGenericError(xmlGenericErrorContext, "new step : ");
9395 if (first != NULL) {
9396 if (*first != NULL)
9397 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9398 (*first)->name);
9399 else
9400 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9401 }
9402 if (last != NULL) {
9403 if (*last != NULL)
9404 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9405 (*last)->name);
9406 else
9407 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9408 }
9409#endif
9410 switch (axis) {
9411 case AXIS_ANCESTOR:
9412#ifdef DEBUG_STEP_NTH
9413 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9414#endif
9415 first = NULL;
9416 next = xmlXPathNextAncestor;
9417 break;
9418 case AXIS_ANCESTOR_OR_SELF:
9419#ifdef DEBUG_STEP_NTH
9420 xmlGenericError(xmlGenericErrorContext,
9421 "axis 'ancestors-or-self' ");
9422#endif
9423 first = NULL;
9424 next = xmlXPathNextAncestorOrSelf;
9425 break;
9426 case AXIS_ATTRIBUTE:
9427#ifdef DEBUG_STEP_NTH
9428 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9429#endif
9430 first = NULL;
9431 last = NULL;
9432 next = xmlXPathNextAttribute;
9433 break;
9434 case AXIS_CHILD:
9435#ifdef DEBUG_STEP_NTH
9436 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9437#endif
9438 last = NULL;
9439 next = xmlXPathNextChild;
9440 break;
9441 case AXIS_DESCENDANT:
9442#ifdef DEBUG_STEP_NTH
9443 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9444#endif
9445 last = NULL;
9446 next = xmlXPathNextDescendant;
9447 break;
9448 case AXIS_DESCENDANT_OR_SELF:
9449#ifdef DEBUG_STEP_NTH
9450 xmlGenericError(xmlGenericErrorContext,
9451 "axis 'descendant-or-self' ");
9452#endif
9453 last = NULL;
9454 next = xmlXPathNextDescendantOrSelf;
9455 break;
9456 case AXIS_FOLLOWING:
9457#ifdef DEBUG_STEP_NTH
9458 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9459#endif
9460 last = NULL;
9461 next = xmlXPathNextFollowing;
9462 break;
9463 case AXIS_FOLLOWING_SIBLING:
9464#ifdef DEBUG_STEP_NTH
9465 xmlGenericError(xmlGenericErrorContext,
9466 "axis 'following-siblings' ");
9467#endif
9468 last = NULL;
9469 next = xmlXPathNextFollowingSibling;
9470 break;
9471 case AXIS_NAMESPACE:
9472#ifdef DEBUG_STEP_NTH
9473 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9474#endif
9475 last = NULL;
9476 first = NULL;
9477 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9478 break;
9479 case AXIS_PARENT:
9480#ifdef DEBUG_STEP_NTH
9481 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9482#endif
9483 first = NULL;
9484 next = xmlXPathNextParent;
9485 break;
9486 case AXIS_PRECEDING:
9487#ifdef DEBUG_STEP_NTH
9488 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9489#endif
9490 first = NULL;
9491 next = xmlXPathNextPrecedingInternal;
9492 break;
9493 case AXIS_PRECEDING_SIBLING:
9494#ifdef DEBUG_STEP_NTH
9495 xmlGenericError(xmlGenericErrorContext,
9496 "axis 'preceding-sibling' ");
9497#endif
9498 first = NULL;
9499 next = xmlXPathNextPrecedingSibling;
9500 break;
9501 case AXIS_SELF:
9502#ifdef DEBUG_STEP_NTH
9503 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9504#endif
9505 first = NULL;
9506 last = NULL;
9507 next = xmlXPathNextSelf;
9508 break;
9509 }
9510 if (next == NULL)
9511 return(0);
9512
9513 nodelist = obj->nodesetval;
9514 if (nodelist == NULL) {
9515 xmlXPathFreeObject(obj);
9516 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9517 return(0);
9518 }
9519 addNode = xmlXPathNodeSetAddUnique;
9520#ifdef DEBUG_STEP_NTH
9521 xmlGenericError(xmlGenericErrorContext,
9522 " context contains %d nodes\n", nodelist->nodeNr);
9523 switch (test) {
9524 case NODE_TEST_NONE:
9525 xmlGenericError(xmlGenericErrorContext,
9526 " searching for none !!!\n");
9527 break;
9528 case NODE_TEST_TYPE:
9529 xmlGenericError(xmlGenericErrorContext,
9530 " searching for type %d\n", type);
9531 break;
9532 case NODE_TEST_PI:
9533 xmlGenericError(xmlGenericErrorContext,
9534 " searching for PI !!!\n");
9535 break;
9536 case NODE_TEST_ALL:
9537 xmlGenericError(xmlGenericErrorContext,
9538 " searching for *\n");
9539 break;
9540 case NODE_TEST_NS:
9541 xmlGenericError(xmlGenericErrorContext,
9542 " searching for namespace %s\n",
9543 prefix);
9544 break;
9545 case NODE_TEST_NAME:
9546 xmlGenericError(xmlGenericErrorContext,
9547 " searching for name %s\n", name);
9548 if (prefix != NULL)
9549 xmlGenericError(xmlGenericErrorContext,
9550 " with namespace %s\n", prefix);
9551 break;
9552 }
9553 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9554#endif
9555 /*
9556 * 2.3 Node Tests
9557 * - For the attribute axis, the principal node type is attribute.
9558 * - For the namespace axis, the principal node type is namespace.
9559 * - For other axes, the principal node type is element.
9560 *
9561 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009562 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009563 * select all element children of the context node
9564 */
9565 tmp = ctxt->context->node;
9566 list = xmlXPathNodeSetCreate(NULL);
9567 for (i = 0; i < nodelist->nodeNr; i++) {
9568 ctxt->context->node = nodelist->nodeTab[i];
9569
9570 cur = NULL;
9571 n = 0;
9572 do {
9573 cur = next(ctxt, cur);
9574 if (cur == NULL)
9575 break;
9576 if ((first != NULL) && (*first == cur))
9577 break;
9578 if (((t % 256) == 0) &&
9579 (first != NULL) && (*first != NULL) &&
9580 (xmlXPathCmpNodes(*first, cur) >= 0))
9581 break;
9582 if ((last != NULL) && (*last == cur))
9583 break;
9584 if (((t % 256) == 0) &&
9585 (last != NULL) && (*last != NULL) &&
9586 (xmlXPathCmpNodes(cur, *last) >= 0))
9587 break;
9588 t++;
9589 switch (test) {
9590 case NODE_TEST_NONE:
9591 ctxt->context->node = tmp;
9592 STRANGE return(0);
9593 case NODE_TEST_TYPE:
9594 if ((cur->type == type) ||
9595 ((type == NODE_TYPE_NODE) &&
9596 ((cur->type == XML_DOCUMENT_NODE) ||
9597 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9598 (cur->type == XML_ELEMENT_NODE) ||
9599 (cur->type == XML_PI_NODE) ||
9600 (cur->type == XML_COMMENT_NODE) ||
9601 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009602 (cur->type == XML_TEXT_NODE))) ||
9603 ((type == NODE_TYPE_TEXT) &&
9604 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009605 n++;
9606 if (n == indx)
9607 addNode(list, cur);
9608 }
9609 break;
9610 case NODE_TEST_PI:
9611 if (cur->type == XML_PI_NODE) {
9612 if ((name != NULL) &&
9613 (!xmlStrEqual(name, cur->name)))
9614 break;
9615 n++;
9616 if (n == indx)
9617 addNode(list, cur);
9618 }
9619 break;
9620 case NODE_TEST_ALL:
9621 if (axis == AXIS_ATTRIBUTE) {
9622 if (cur->type == XML_ATTRIBUTE_NODE) {
9623 n++;
9624 if (n == indx)
9625 addNode(list, cur);
9626 }
9627 } else if (axis == AXIS_NAMESPACE) {
9628 if (cur->type == XML_NAMESPACE_DECL) {
9629 n++;
9630 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009631 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9632 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009633 }
9634 } else {
9635 if (cur->type == XML_ELEMENT_NODE) {
9636 if (prefix == NULL) {
9637 n++;
9638 if (n == indx)
9639 addNode(list, cur);
9640 } else if ((cur->ns != NULL) &&
9641 (xmlStrEqual(URI, cur->ns->href))) {
9642 n++;
9643 if (n == indx)
9644 addNode(list, cur);
9645 }
9646 }
9647 }
9648 break;
9649 case NODE_TEST_NS:{
9650 TODO;
9651 break;
9652 }
9653 case NODE_TEST_NAME:
9654 switch (cur->type) {
9655 case XML_ELEMENT_NODE:
9656 if (xmlStrEqual(name, cur->name)) {
9657 if (prefix == NULL) {
9658 if (cur->ns == NULL) {
9659 n++;
9660 if (n == indx)
9661 addNode(list, cur);
9662 }
9663 } else {
9664 if ((cur->ns != NULL) &&
9665 (xmlStrEqual(URI,
9666 cur->ns->href))) {
9667 n++;
9668 if (n == indx)
9669 addNode(list, cur);
9670 }
9671 }
9672 }
9673 break;
9674 case XML_ATTRIBUTE_NODE:{
9675 xmlAttrPtr attr = (xmlAttrPtr) cur;
9676
9677 if (xmlStrEqual(name, attr->name)) {
9678 if (prefix == NULL) {
9679 if ((attr->ns == NULL) ||
9680 (attr->ns->prefix == NULL)) {
9681 n++;
9682 if (n == indx)
9683 addNode(list, cur);
9684 }
9685 } else {
9686 if ((attr->ns != NULL) &&
9687 (xmlStrEqual(URI,
9688 attr->ns->
9689 href))) {
9690 n++;
9691 if (n == indx)
9692 addNode(list, cur);
9693 }
9694 }
9695 }
9696 break;
9697 }
9698 case XML_NAMESPACE_DECL:
9699 if (cur->type == XML_NAMESPACE_DECL) {
9700 xmlNsPtr ns = (xmlNsPtr) cur;
9701
9702 if ((ns->prefix != NULL) && (name != NULL)
9703 && (xmlStrEqual(ns->prefix, name))) {
9704 n++;
9705 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009706 xmlXPathNodeSetAddNs(list,
9707 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009708 }
9709 }
9710 break;
9711 default:
9712 break;
9713 }
9714 break;
9715 break;
9716 }
9717 } while (n < indx);
9718 }
9719 ctxt->context->node = tmp;
9720#ifdef DEBUG_STEP_NTH
9721 xmlGenericError(xmlGenericErrorContext,
9722 "\nExamined %d nodes, found %d nodes at that step\n",
9723 t, list->nodeNr);
9724#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009725 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009726 if ((obj->boolval) && (obj->user != NULL)) {
9727 ctxt->value->boolval = 1;
9728 ctxt->value->user = obj->user;
9729 obj->user = NULL;
9730 obj->boolval = 0;
9731 }
9732 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009733 return(t);
9734}
9735
9736/**
9737 * xmlXPathCompOpEvalFirst:
9738 * @ctxt: the XPath parser context with the compiled expression
9739 * @op: an XPath compiled operation
9740 * @first: the first elem found so far
9741 *
9742 * Evaluate the Precompiled XPath operation searching only the first
9743 * element in document order
9744 *
9745 * Returns the number of examined objects.
9746 */
9747static int
9748xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9749 xmlXPathStepOpPtr op, xmlNodePtr * first)
9750{
9751 int total = 0, cur;
9752 xmlXPathCompExprPtr comp;
9753 xmlXPathObjectPtr arg1, arg2;
9754
Daniel Veillard556c6682001-10-06 09:59:51 +00009755 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009756 comp = ctxt->comp;
9757 switch (op->op) {
9758 case XPATH_OP_END:
9759 return (0);
9760 case XPATH_OP_UNION:
9761 total =
9762 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9763 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009764 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009765 if ((ctxt->value != NULL)
9766 && (ctxt->value->type == XPATH_NODESET)
9767 && (ctxt->value->nodesetval != NULL)
9768 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9769 /*
9770 * limit tree traversing to first node in the result
9771 */
9772 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9773 *first = ctxt->value->nodesetval->nodeTab[0];
9774 }
9775 cur =
9776 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9777 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009778 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009779 CHECK_TYPE0(XPATH_NODESET);
9780 arg2 = valuePop(ctxt);
9781
9782 CHECK_TYPE0(XPATH_NODESET);
9783 arg1 = valuePop(ctxt);
9784
9785 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9786 arg2->nodesetval);
9787 valuePush(ctxt, arg1);
9788 xmlXPathFreeObject(arg2);
9789 /* optimizer */
9790 if (total > cur)
9791 xmlXPathCompSwap(op);
9792 return (total + cur);
9793 case XPATH_OP_ROOT:
9794 xmlXPathRoot(ctxt);
9795 return (0);
9796 case XPATH_OP_NODE:
9797 if (op->ch1 != -1)
9798 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009799 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009800 if (op->ch2 != -1)
9801 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009802 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009803 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9804 return (total);
9805 case XPATH_OP_RESET:
9806 if (op->ch1 != -1)
9807 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009808 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009809 if (op->ch2 != -1)
9810 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009811 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009812 ctxt->context->node = NULL;
9813 return (total);
9814 case XPATH_OP_COLLECT:{
9815 if (op->ch1 == -1)
9816 return (total);
9817
9818 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009819 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009820
9821 /*
9822 * Optimization for [n] selection where n is a number
9823 */
9824 if ((op->ch2 != -1) &&
9825 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9826 (comp->steps[op->ch2].ch1 == -1) &&
9827 (comp->steps[op->ch2].ch2 != -1) &&
9828 (comp->steps[comp->steps[op->ch2].ch2].op ==
9829 XPATH_OP_VALUE)) {
9830 xmlXPathObjectPtr val;
9831
9832 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9833 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9834 int indx = (int) val->floatval;
9835
9836 if (val->floatval == (float) indx) {
9837 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9838 first, NULL);
9839 return (total);
9840 }
9841 }
9842 }
9843 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9844 return (total);
9845 }
9846 case XPATH_OP_VALUE:
9847 valuePush(ctxt,
9848 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9849 return (0);
9850 case XPATH_OP_SORT:
9851 if (op->ch1 != -1)
9852 total +=
9853 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9854 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009855 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009856 if ((ctxt->value != NULL)
9857 && (ctxt->value->type == XPATH_NODESET)
9858 && (ctxt->value->nodesetval != NULL))
9859 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9860 return (total);
9861 default:
9862 return (xmlXPathCompOpEval(ctxt, op));
9863 }
9864}
9865
9866/**
9867 * xmlXPathCompOpEvalLast:
9868 * @ctxt: the XPath parser context with the compiled expression
9869 * @op: an XPath compiled operation
9870 * @last: the last elem found so far
9871 *
9872 * Evaluate the Precompiled XPath operation searching only the last
9873 * element in document order
9874 *
William M. Brack08171912003-12-29 02:52:11 +00009875 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +00009876 */
9877static int
9878xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9879 xmlNodePtr * last)
9880{
9881 int total = 0, cur;
9882 xmlXPathCompExprPtr comp;
9883 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +00009884 xmlNodePtr bak;
9885 xmlDocPtr bakd;
9886 int pp;
9887 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009888
Daniel Veillard556c6682001-10-06 09:59:51 +00009889 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009890 comp = ctxt->comp;
9891 switch (op->op) {
9892 case XPATH_OP_END:
9893 return (0);
9894 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +00009895 bakd = ctxt->context->doc;
9896 bak = ctxt->context->node;
9897 pp = ctxt->context->proximityPosition;
9898 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009899 total =
9900 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009901 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009902 if ((ctxt->value != NULL)
9903 && (ctxt->value->type == XPATH_NODESET)
9904 && (ctxt->value->nodesetval != NULL)
9905 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9906 /*
9907 * limit tree traversing to first node in the result
9908 */
9909 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9910 *last =
9911 ctxt->value->nodesetval->nodeTab[ctxt->value->
9912 nodesetval->nodeNr -
9913 1];
9914 }
William M. Brackce4fc562004-01-22 02:47:18 +00009915 ctxt->context->doc = bakd;
9916 ctxt->context->node = bak;
9917 ctxt->context->proximityPosition = pp;
9918 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009919 cur =
9920 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009921 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009922 if ((ctxt->value != NULL)
9923 && (ctxt->value->type == XPATH_NODESET)
9924 && (ctxt->value->nodesetval != NULL)
9925 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9926 }
9927 CHECK_TYPE0(XPATH_NODESET);
9928 arg2 = valuePop(ctxt);
9929
9930 CHECK_TYPE0(XPATH_NODESET);
9931 arg1 = valuePop(ctxt);
9932
9933 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9934 arg2->nodesetval);
9935 valuePush(ctxt, arg1);
9936 xmlXPathFreeObject(arg2);
9937 /* optimizer */
9938 if (total > cur)
9939 xmlXPathCompSwap(op);
9940 return (total + cur);
9941 case XPATH_OP_ROOT:
9942 xmlXPathRoot(ctxt);
9943 return (0);
9944 case XPATH_OP_NODE:
9945 if (op->ch1 != -1)
9946 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009947 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009948 if (op->ch2 != -1)
9949 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009950 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009951 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9952 return (total);
9953 case XPATH_OP_RESET:
9954 if (op->ch1 != -1)
9955 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009956 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009957 if (op->ch2 != -1)
9958 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009959 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009960 ctxt->context->node = NULL;
9961 return (total);
9962 case XPATH_OP_COLLECT:{
9963 if (op->ch1 == -1)
9964 return (0);
9965
9966 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009967 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009968
9969 /*
9970 * Optimization for [n] selection where n is a number
9971 */
9972 if ((op->ch2 != -1) &&
9973 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9974 (comp->steps[op->ch2].ch1 == -1) &&
9975 (comp->steps[op->ch2].ch2 != -1) &&
9976 (comp->steps[comp->steps[op->ch2].ch2].op ==
9977 XPATH_OP_VALUE)) {
9978 xmlXPathObjectPtr val;
9979
9980 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9981 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9982 int indx = (int) val->floatval;
9983
9984 if (val->floatval == (float) indx) {
9985 total +=
9986 xmlXPathNodeCollectAndTestNth(ctxt, op,
9987 indx, NULL,
9988 last);
9989 return (total);
9990 }
9991 }
9992 }
9993 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9994 return (total);
9995 }
9996 case XPATH_OP_VALUE:
9997 valuePush(ctxt,
9998 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9999 return (0);
10000 case XPATH_OP_SORT:
10001 if (op->ch1 != -1)
10002 total +=
10003 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10004 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010005 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010006 if ((ctxt->value != NULL)
10007 && (ctxt->value->type == XPATH_NODESET)
10008 && (ctxt->value->nodesetval != NULL))
10009 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10010 return (total);
10011 default:
10012 return (xmlXPathCompOpEval(ctxt, op));
10013 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010014}
10015
Owen Taylor3473f882001-02-23 17:55:21 +000010016/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010017 * xmlXPathCompOpEval:
10018 * @ctxt: the XPath parser context with the compiled expression
10019 * @op: an XPath compiled operation
10020 *
10021 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010022 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010023 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010024static int
10025xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10026{
10027 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010028 int equal, ret;
10029 xmlXPathCompExprPtr comp;
10030 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010031 xmlNodePtr bak;
10032 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010033 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010034 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010035
Daniel Veillard556c6682001-10-06 09:59:51 +000010036 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010037 comp = ctxt->comp;
10038 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010039 case XPATH_OP_END:
10040 return (0);
10041 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010042 bakd = ctxt->context->doc;
10043 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010044 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010045 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010046 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010047 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010048 xmlXPathBooleanFunction(ctxt, 1);
10049 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10050 return (total);
10051 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010052 ctxt->context->doc = bakd;
10053 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010054 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010055 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010056 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010057 if (ctxt->error) {
10058 xmlXPathFreeObject(arg2);
10059 return(0);
10060 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010061 xmlXPathBooleanFunction(ctxt, 1);
10062 arg1 = valuePop(ctxt);
10063 arg1->boolval &= arg2->boolval;
10064 valuePush(ctxt, arg1);
10065 xmlXPathFreeObject(arg2);
10066 return (total);
10067 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010068 bakd = ctxt->context->doc;
10069 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010070 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010071 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010072 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010073 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010074 xmlXPathBooleanFunction(ctxt, 1);
10075 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10076 return (total);
10077 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010078 ctxt->context->doc = bakd;
10079 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010080 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010081 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010082 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010083 if (ctxt->error) {
10084 xmlXPathFreeObject(arg2);
10085 return(0);
10086 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010087 xmlXPathBooleanFunction(ctxt, 1);
10088 arg1 = valuePop(ctxt);
10089 arg1->boolval |= arg2->boolval;
10090 valuePush(ctxt, arg1);
10091 xmlXPathFreeObject(arg2);
10092 return (total);
10093 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010094 bakd = ctxt->context->doc;
10095 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010096 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010097 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010098 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010099 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010100 ctxt->context->doc = bakd;
10101 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010102 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010103 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010104 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010105 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010106 if (op->value)
10107 equal = xmlXPathEqualValues(ctxt);
10108 else
10109 equal = xmlXPathNotEqualValues(ctxt);
10110 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010111 return (total);
10112 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010113 bakd = ctxt->context->doc;
10114 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010115 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010116 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010117 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010118 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010119 ctxt->context->doc = bakd;
10120 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010121 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010122 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010123 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010124 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010125 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10126 valuePush(ctxt, xmlXPathNewBoolean(ret));
10127 return (total);
10128 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010129 bakd = ctxt->context->doc;
10130 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010131 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010132 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010133 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010134 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010135 if (op->ch2 != -1) {
10136 ctxt->context->doc = bakd;
10137 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010138 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010139 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010140 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010141 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010142 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010143 if (op->value == 0)
10144 xmlXPathSubValues(ctxt);
10145 else if (op->value == 1)
10146 xmlXPathAddValues(ctxt);
10147 else if (op->value == 2)
10148 xmlXPathValueFlipSign(ctxt);
10149 else if (op->value == 3) {
10150 CAST_TO_NUMBER;
10151 CHECK_TYPE0(XPATH_NUMBER);
10152 }
10153 return (total);
10154 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010155 bakd = ctxt->context->doc;
10156 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010157 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010158 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010159 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010160 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010161 ctxt->context->doc = bakd;
10162 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010163 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010164 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010165 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010166 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010167 if (op->value == 0)
10168 xmlXPathMultValues(ctxt);
10169 else if (op->value == 1)
10170 xmlXPathDivValues(ctxt);
10171 else if (op->value == 2)
10172 xmlXPathModValues(ctxt);
10173 return (total);
10174 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010175 bakd = ctxt->context->doc;
10176 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010177 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010178 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010179 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010180 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010181 ctxt->context->doc = bakd;
10182 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010183 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010184 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010185 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010186 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010187 CHECK_TYPE0(XPATH_NODESET);
10188 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010189
Daniel Veillardf06307e2001-07-03 10:35:50 +000010190 CHECK_TYPE0(XPATH_NODESET);
10191 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010192
Daniel Veillardf06307e2001-07-03 10:35:50 +000010193 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10194 arg2->nodesetval);
10195 valuePush(ctxt, arg1);
10196 xmlXPathFreeObject(arg2);
10197 return (total);
10198 case XPATH_OP_ROOT:
10199 xmlXPathRoot(ctxt);
10200 return (total);
10201 case XPATH_OP_NODE:
10202 if (op->ch1 != -1)
10203 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010204 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010205 if (op->ch2 != -1)
10206 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010207 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010208 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10209 return (total);
10210 case XPATH_OP_RESET:
10211 if (op->ch1 != -1)
10212 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010213 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010214 if (op->ch2 != -1)
10215 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010216 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010217 ctxt->context->node = NULL;
10218 return (total);
10219 case XPATH_OP_COLLECT:{
10220 if (op->ch1 == -1)
10221 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010222
Daniel Veillardf06307e2001-07-03 10:35:50 +000010223 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010224 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010225
Daniel Veillardf06307e2001-07-03 10:35:50 +000010226 /*
10227 * Optimization for [n] selection where n is a number
10228 */
10229 if ((op->ch2 != -1) &&
10230 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10231 (comp->steps[op->ch2].ch1 == -1) &&
10232 (comp->steps[op->ch2].ch2 != -1) &&
10233 (comp->steps[comp->steps[op->ch2].ch2].op ==
10234 XPATH_OP_VALUE)) {
10235 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010236
Daniel Veillardf06307e2001-07-03 10:35:50 +000010237 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10238 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10239 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010240
Daniel Veillardf06307e2001-07-03 10:35:50 +000010241 if (val->floatval == (float) indx) {
10242 total +=
10243 xmlXPathNodeCollectAndTestNth(ctxt, op,
10244 indx, NULL,
10245 NULL);
10246 return (total);
10247 }
10248 }
10249 }
10250 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10251 return (total);
10252 }
10253 case XPATH_OP_VALUE:
10254 valuePush(ctxt,
10255 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10256 return (total);
10257 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010258 xmlXPathObjectPtr val;
10259
Daniel Veillardf06307e2001-07-03 10:35:50 +000010260 if (op->ch1 != -1)
10261 total +=
10262 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010263 if (op->value5 == NULL) {
10264 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10265 if (val == NULL) {
10266 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10267 return(0);
10268 }
10269 valuePush(ctxt, val);
10270 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010271 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010272
Daniel Veillardf06307e2001-07-03 10:35:50 +000010273 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10274 if (URI == NULL) {
10275 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010276 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010277 op->value4, op->value5);
10278 return (total);
10279 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010280 val = xmlXPathVariableLookupNS(ctxt->context,
10281 op->value4, URI);
10282 if (val == NULL) {
10283 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10284 return(0);
10285 }
10286 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010287 }
10288 return (total);
10289 }
10290 case XPATH_OP_FUNCTION:{
10291 xmlXPathFunction func;
10292 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010293 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010294
10295 if (op->ch1 != -1)
10296 total +=
10297 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010298 if (ctxt->valueNr < op->value) {
10299 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010300 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010301 ctxt->error = XPATH_INVALID_OPERAND;
10302 return (total);
10303 }
10304 for (i = 0; i < op->value; i++)
10305 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10306 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010307 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010308 ctxt->error = XPATH_INVALID_OPERAND;
10309 return (total);
10310 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010311 if (op->cache != NULL)
10312 func = (xmlXPathFunction) op->cache;
10313 else {
10314 const xmlChar *URI = NULL;
10315
10316 if (op->value5 == NULL)
10317 func =
10318 xmlXPathFunctionLookup(ctxt->context,
10319 op->value4);
10320 else {
10321 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10322 if (URI == NULL) {
10323 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010324 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010325 op->value4, op->value5);
10326 return (total);
10327 }
10328 func = xmlXPathFunctionLookupNS(ctxt->context,
10329 op->value4, URI);
10330 }
10331 if (func == NULL) {
10332 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010333 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010334 op->value4);
10335 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010336 }
10337 op->cache = (void *) func;
10338 op->cacheURI = (void *) URI;
10339 }
10340 oldFunc = ctxt->context->function;
10341 oldFuncURI = ctxt->context->functionURI;
10342 ctxt->context->function = op->value4;
10343 ctxt->context->functionURI = op->cacheURI;
10344 func(ctxt, op->value);
10345 ctxt->context->function = oldFunc;
10346 ctxt->context->functionURI = oldFuncURI;
10347 return (total);
10348 }
10349 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010350 bakd = ctxt->context->doc;
10351 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010352 if (op->ch1 != -1)
10353 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010354 ctxt->context->doc = bakd;
10355 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010356 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010357 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010358 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010359 ctxt->context->doc = bakd;
10360 ctxt->context->node = bak;
10361 CHECK_ERROR0;
10362 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010363 return (total);
10364 case XPATH_OP_PREDICATE:
10365 case XPATH_OP_FILTER:{
10366 xmlXPathObjectPtr res;
10367 xmlXPathObjectPtr obj, tmp;
10368 xmlNodeSetPtr newset = NULL;
10369 xmlNodeSetPtr oldset;
10370 xmlNodePtr oldnode;
10371 int i;
10372
10373 /*
10374 * Optimization for ()[1] selection i.e. the first elem
10375 */
10376 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10377 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10378 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10379 xmlXPathObjectPtr val;
10380
10381 val = comp->steps[op->ch2].value4;
10382 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10383 (val->floatval == 1.0)) {
10384 xmlNodePtr first = NULL;
10385
10386 total +=
10387 xmlXPathCompOpEvalFirst(ctxt,
10388 &comp->steps[op->ch1],
10389 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010390 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010391 /*
10392 * The nodeset should be in document order,
10393 * Keep only the first value
10394 */
10395 if ((ctxt->value != NULL) &&
10396 (ctxt->value->type == XPATH_NODESET) &&
10397 (ctxt->value->nodesetval != NULL) &&
10398 (ctxt->value->nodesetval->nodeNr > 1))
10399 ctxt->value->nodesetval->nodeNr = 1;
10400 return (total);
10401 }
10402 }
10403 /*
10404 * Optimization for ()[last()] selection i.e. the last elem
10405 */
10406 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10407 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10408 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10409 int f = comp->steps[op->ch2].ch1;
10410
10411 if ((f != -1) &&
10412 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10413 (comp->steps[f].value5 == NULL) &&
10414 (comp->steps[f].value == 0) &&
10415 (comp->steps[f].value4 != NULL) &&
10416 (xmlStrEqual
10417 (comp->steps[f].value4, BAD_CAST "last"))) {
10418 xmlNodePtr last = NULL;
10419
10420 total +=
10421 xmlXPathCompOpEvalLast(ctxt,
10422 &comp->steps[op->ch1],
10423 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010424 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010425 /*
10426 * The nodeset should be in document order,
10427 * Keep only the last value
10428 */
10429 if ((ctxt->value != NULL) &&
10430 (ctxt->value->type == XPATH_NODESET) &&
10431 (ctxt->value->nodesetval != NULL) &&
10432 (ctxt->value->nodesetval->nodeTab != NULL) &&
10433 (ctxt->value->nodesetval->nodeNr > 1)) {
10434 ctxt->value->nodesetval->nodeTab[0] =
10435 ctxt->value->nodesetval->nodeTab[ctxt->
10436 value->
10437 nodesetval->
10438 nodeNr -
10439 1];
10440 ctxt->value->nodesetval->nodeNr = 1;
10441 }
10442 return (total);
10443 }
10444 }
10445
10446 if (op->ch1 != -1)
10447 total +=
10448 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010449 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010450 if (op->ch2 == -1)
10451 return (total);
10452 if (ctxt->value == NULL)
10453 return (total);
10454
10455 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010456
10457#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010458 /*
10459 * Hum are we filtering the result of an XPointer expression
10460 */
10461 if (ctxt->value->type == XPATH_LOCATIONSET) {
10462 xmlLocationSetPtr newlocset = NULL;
10463 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010464
Daniel Veillardf06307e2001-07-03 10:35:50 +000010465 /*
10466 * Extract the old locset, and then evaluate the result of the
10467 * expression for all the element in the locset. use it to grow
10468 * up a new locset.
10469 */
10470 CHECK_TYPE0(XPATH_LOCATIONSET);
10471 obj = valuePop(ctxt);
10472 oldlocset = obj->user;
10473 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010474
Daniel Veillardf06307e2001-07-03 10:35:50 +000010475 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10476 ctxt->context->contextSize = 0;
10477 ctxt->context->proximityPosition = 0;
10478 if (op->ch2 != -1)
10479 total +=
10480 xmlXPathCompOpEval(ctxt,
10481 &comp->steps[op->ch2]);
10482 res = valuePop(ctxt);
10483 if (res != NULL)
10484 xmlXPathFreeObject(res);
10485 valuePush(ctxt, obj);
10486 CHECK_ERROR0;
10487 return (total);
10488 }
10489 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010490
Daniel Veillardf06307e2001-07-03 10:35:50 +000010491 for (i = 0; i < oldlocset->locNr; i++) {
10492 /*
10493 * Run the evaluation with a node list made of a
10494 * single item in the nodelocset.
10495 */
10496 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010497 ctxt->context->contextSize = oldlocset->locNr;
10498 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010499 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10500 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010501
Daniel Veillardf06307e2001-07-03 10:35:50 +000010502 if (op->ch2 != -1)
10503 total +=
10504 xmlXPathCompOpEval(ctxt,
10505 &comp->steps[op->ch2]);
10506 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010507
Daniel Veillardf06307e2001-07-03 10:35:50 +000010508 /*
10509 * The result of the evaluation need to be tested to
10510 * decided whether the filter succeeded or not
10511 */
10512 res = valuePop(ctxt);
10513 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10514 xmlXPtrLocationSetAdd(newlocset,
10515 xmlXPathObjectCopy
10516 (oldlocset->locTab[i]));
10517 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010518
Daniel Veillardf06307e2001-07-03 10:35:50 +000010519 /*
10520 * Cleanup
10521 */
10522 if (res != NULL)
10523 xmlXPathFreeObject(res);
10524 if (ctxt->value == tmp) {
10525 res = valuePop(ctxt);
10526 xmlXPathFreeObject(res);
10527 }
10528
10529 ctxt->context->node = NULL;
10530 }
10531
10532 /*
10533 * The result is used as the new evaluation locset.
10534 */
10535 xmlXPathFreeObject(obj);
10536 ctxt->context->node = NULL;
10537 ctxt->context->contextSize = -1;
10538 ctxt->context->proximityPosition = -1;
10539 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10540 ctxt->context->node = oldnode;
10541 return (total);
10542 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010543#endif /* LIBXML_XPTR_ENABLED */
10544
Daniel Veillardf06307e2001-07-03 10:35:50 +000010545 /*
10546 * Extract the old set, and then evaluate the result of the
10547 * expression for all the element in the set. use it to grow
10548 * up a new set.
10549 */
10550 CHECK_TYPE0(XPATH_NODESET);
10551 obj = valuePop(ctxt);
10552 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010553
Daniel Veillardf06307e2001-07-03 10:35:50 +000010554 oldnode = ctxt->context->node;
10555 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010556
Daniel Veillardf06307e2001-07-03 10:35:50 +000010557 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10558 ctxt->context->contextSize = 0;
10559 ctxt->context->proximityPosition = 0;
10560 if (op->ch2 != -1)
10561 total +=
10562 xmlXPathCompOpEval(ctxt,
10563 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010564 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010565 res = valuePop(ctxt);
10566 if (res != NULL)
10567 xmlXPathFreeObject(res);
10568 valuePush(ctxt, obj);
10569 ctxt->context->node = oldnode;
10570 CHECK_ERROR0;
10571 } else {
10572 /*
10573 * Initialize the new set.
10574 */
10575 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010576
Daniel Veillardf06307e2001-07-03 10:35:50 +000010577 for (i = 0; i < oldset->nodeNr; i++) {
10578 /*
10579 * Run the evaluation with a node list made of
10580 * a single item in the nodeset.
10581 */
10582 ctxt->context->node = oldset->nodeTab[i];
10583 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10584 valuePush(ctxt, tmp);
10585 ctxt->context->contextSize = oldset->nodeNr;
10586 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010587
Daniel Veillardf06307e2001-07-03 10:35:50 +000010588 if (op->ch2 != -1)
10589 total +=
10590 xmlXPathCompOpEval(ctxt,
10591 &comp->steps[op->ch2]);
10592 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010593
Daniel Veillardf06307e2001-07-03 10:35:50 +000010594 /*
William M. Brack08171912003-12-29 02:52:11 +000010595 * The result of the evaluation needs to be tested to
10596 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010597 */
10598 res = valuePop(ctxt);
10599 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10600 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10601 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010602
Daniel Veillardf06307e2001-07-03 10:35:50 +000010603 /*
10604 * Cleanup
10605 */
10606 if (res != NULL)
10607 xmlXPathFreeObject(res);
10608 if (ctxt->value == tmp) {
10609 res = valuePop(ctxt);
10610 xmlXPathFreeObject(res);
10611 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010612
Daniel Veillardf06307e2001-07-03 10:35:50 +000010613 ctxt->context->node = NULL;
10614 }
10615
10616 /*
10617 * The result is used as the new evaluation set.
10618 */
10619 xmlXPathFreeObject(obj);
10620 ctxt->context->node = NULL;
10621 ctxt->context->contextSize = -1;
10622 ctxt->context->proximityPosition = -1;
10623 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10624 }
10625 ctxt->context->node = oldnode;
10626 return (total);
10627 }
10628 case XPATH_OP_SORT:
10629 if (op->ch1 != -1)
10630 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010631 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010632 if ((ctxt->value != NULL) &&
10633 (ctxt->value->type == XPATH_NODESET) &&
10634 (ctxt->value->nodesetval != NULL))
10635 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10636 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010637#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010638 case XPATH_OP_RANGETO:{
10639 xmlXPathObjectPtr range;
10640 xmlXPathObjectPtr res, obj;
10641 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010642 xmlLocationSetPtr newlocset = NULL;
10643 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010644 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000010645 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010646
Daniel Veillardf06307e2001-07-03 10:35:50 +000010647 if (op->ch1 != -1)
10648 total +=
10649 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10650 if (op->ch2 == -1)
10651 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010652
William M. Brack08171912003-12-29 02:52:11 +000010653 if (ctxt->value->type == XPATH_LOCATIONSET) {
10654 /*
10655 * Extract the old locset, and then evaluate the result of the
10656 * expression for all the element in the locset. use it to grow
10657 * up a new locset.
10658 */
10659 CHECK_TYPE0(XPATH_LOCATIONSET);
10660 obj = valuePop(ctxt);
10661 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010662
William M. Brack08171912003-12-29 02:52:11 +000010663 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000010664 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000010665 ctxt->context->contextSize = 0;
10666 ctxt->context->proximityPosition = 0;
10667 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10668 res = valuePop(ctxt);
10669 if (res != NULL)
10670 xmlXPathFreeObject(res);
10671 valuePush(ctxt, obj);
10672 CHECK_ERROR0;
10673 return (total);
10674 }
10675 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010676
William M. Brack08171912003-12-29 02:52:11 +000010677 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010678 /*
William M. Brack08171912003-12-29 02:52:11 +000010679 * Run the evaluation with a node list made of a
10680 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010681 */
William M. Brackf7eb7942003-12-31 07:59:17 +000010682 ctxt->context->node = oldlocset->locTab[i]->user;
10683 ctxt->context->contextSize = oldlocset->locNr;
10684 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010685 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10686 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010687
Daniel Veillardf06307e2001-07-03 10:35:50 +000010688 if (op->ch2 != -1)
10689 total +=
10690 xmlXPathCompOpEval(ctxt,
10691 &comp->steps[op->ch2]);
10692 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010693
Daniel Veillardf06307e2001-07-03 10:35:50 +000010694 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000010695 if (res->type == XPATH_LOCATIONSET) {
10696 xmlLocationSetPtr rloc =
10697 (xmlLocationSetPtr)res->user;
10698 for (j=0; j<rloc->locNr; j++) {
10699 range = xmlXPtrNewRange(
10700 oldlocset->locTab[i]->user,
10701 oldlocset->locTab[i]->index,
10702 rloc->locTab[j]->user2,
10703 rloc->locTab[j]->index2);
10704 if (range != NULL) {
10705 xmlXPtrLocationSetAdd(newlocset, range);
10706 }
10707 }
10708 } else {
10709 range = xmlXPtrNewRangeNodeObject(
10710 (xmlNodePtr)oldlocset->locTab[i]->user, res);
10711 if (range != NULL) {
10712 xmlXPtrLocationSetAdd(newlocset,range);
10713 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010714 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010715
Daniel Veillardf06307e2001-07-03 10:35:50 +000010716 /*
10717 * Cleanup
10718 */
10719 if (res != NULL)
10720 xmlXPathFreeObject(res);
10721 if (ctxt->value == tmp) {
10722 res = valuePop(ctxt);
10723 xmlXPathFreeObject(res);
10724 }
10725
10726 ctxt->context->node = NULL;
10727 }
William M. Brack72ee48d2003-12-30 08:30:19 +000010728 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000010729 CHECK_TYPE0(XPATH_NODESET);
10730 obj = valuePop(ctxt);
10731 oldset = obj->nodesetval;
10732 ctxt->context->node = NULL;
10733
10734 newlocset = xmlXPtrLocationSetCreate(NULL);
10735
10736 if (oldset != NULL) {
10737 for (i = 0; i < oldset->nodeNr; i++) {
10738 /*
10739 * Run the evaluation with a node list made of a single item
10740 * in the nodeset.
10741 */
10742 ctxt->context->node = oldset->nodeTab[i];
10743 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10744 valuePush(ctxt, tmp);
10745
10746 if (op->ch2 != -1)
10747 total +=
10748 xmlXPathCompOpEval(ctxt,
10749 &comp->steps[op->ch2]);
10750 CHECK_ERROR0;
10751
William M. Brack08171912003-12-29 02:52:11 +000010752 res = valuePop(ctxt);
10753 range =
10754 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10755 res);
10756 if (range != NULL) {
10757 xmlXPtrLocationSetAdd(newlocset, range);
10758 }
10759
10760 /*
10761 * Cleanup
10762 */
10763 if (res != NULL)
10764 xmlXPathFreeObject(res);
10765 if (ctxt->value == tmp) {
10766 res = valuePop(ctxt);
10767 xmlXPathFreeObject(res);
10768 }
10769
10770 ctxt->context->node = NULL;
10771 }
10772 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010773 }
10774
10775 /*
10776 * The result is used as the new evaluation set.
10777 */
10778 xmlXPathFreeObject(obj);
10779 ctxt->context->node = NULL;
10780 ctxt->context->contextSize = -1;
10781 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010782 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010783 return (total);
10784 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010785#endif /* LIBXML_XPTR_ENABLED */
10786 }
10787 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010788 "XPath: unknown precompiled operation %d\n", op->op);
10789 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010790}
10791
10792/**
10793 * xmlXPathRunEval:
10794 * @ctxt: the XPath parser context with the compiled expression
10795 *
10796 * Evaluate the Precompiled XPath expression in the given context.
10797 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010798static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010799xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10800 xmlXPathCompExprPtr comp;
10801
10802 if ((ctxt == NULL) || (ctxt->comp == NULL))
10803 return;
10804
10805 if (ctxt->valueTab == NULL) {
10806 /* Allocate the value stack */
10807 ctxt->valueTab = (xmlXPathObjectPtr *)
10808 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10809 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010810 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010811 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010812 }
10813 ctxt->valueNr = 0;
10814 ctxt->valueMax = 10;
10815 ctxt->value = NULL;
10816 }
10817 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010818 if(comp->last < 0) {
10819 xmlGenericError(xmlGenericErrorContext,
10820 "xmlXPathRunEval: last is less than zero\n");
10821 return;
10822 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010823 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10824}
10825
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010826/************************************************************************
10827 * *
10828 * Public interfaces *
10829 * *
10830 ************************************************************************/
10831
10832/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010833 * xmlXPathEvalPredicate:
10834 * @ctxt: the XPath context
10835 * @res: the Predicate Expression evaluation result
10836 *
10837 * Evaluate a predicate result for the current node.
10838 * A PredicateExpr is evaluated by evaluating the Expr and converting
10839 * the result to a boolean. If the result is a number, the result will
10840 * be converted to true if the number is equal to the position of the
10841 * context node in the context node list (as returned by the position
10842 * function) and will be converted to false otherwise; if the result
10843 * is not a number, then the result will be converted as if by a call
10844 * to the boolean function.
10845 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010846 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010847 */
10848int
10849xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10850 if (res == NULL) return(0);
10851 switch (res->type) {
10852 case XPATH_BOOLEAN:
10853 return(res->boolval);
10854 case XPATH_NUMBER:
10855 return(res->floatval == ctxt->proximityPosition);
10856 case XPATH_NODESET:
10857 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010858 if (res->nodesetval == NULL)
10859 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010860 return(res->nodesetval->nodeNr != 0);
10861 case XPATH_STRING:
10862 return((res->stringval != NULL) &&
10863 (xmlStrlen(res->stringval) != 0));
10864 default:
10865 STRANGE
10866 }
10867 return(0);
10868}
10869
10870/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010871 * xmlXPathEvaluatePredicateResult:
10872 * @ctxt: the XPath Parser context
10873 * @res: the Predicate Expression evaluation result
10874 *
10875 * Evaluate a predicate result for the current node.
10876 * A PredicateExpr is evaluated by evaluating the Expr and converting
10877 * the result to a boolean. If the result is a number, the result will
10878 * be converted to true if the number is equal to the position of the
10879 * context node in the context node list (as returned by the position
10880 * function) and will be converted to false otherwise; if the result
10881 * is not a number, then the result will be converted as if by a call
10882 * to the boolean function.
10883 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010884 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010885 */
10886int
10887xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10888 xmlXPathObjectPtr res) {
10889 if (res == NULL) return(0);
10890 switch (res->type) {
10891 case XPATH_BOOLEAN:
10892 return(res->boolval);
10893 case XPATH_NUMBER:
10894 return(res->floatval == ctxt->context->proximityPosition);
10895 case XPATH_NODESET:
10896 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010897 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010898 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010899 return(res->nodesetval->nodeNr != 0);
10900 case XPATH_STRING:
10901 return((res->stringval != NULL) &&
10902 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000010903#ifdef LIBXML_XPTR_ENABLED
10904 case XPATH_LOCATIONSET:{
10905 xmlLocationSetPtr ptr = res->user;
10906 if (ptr == NULL)
10907 return(0);
10908 return (ptr->locNr != 0);
10909 }
10910#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010911 default:
10912 STRANGE
10913 }
10914 return(0);
10915}
10916
10917/**
Daniel Veillard4773df22004-01-23 13:15:13 +000010918 * xmlXPathCtxtCompile:
10919 * @ctxt: an XPath context
10920 * @str: the XPath expression
10921 *
10922 * Compile an XPath expression
10923 *
10924 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
10925 * the caller has to free the object.
10926 */
10927xmlXPathCompExprPtr
10928xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
10929 xmlXPathParserContextPtr pctxt;
10930 xmlXPathCompExprPtr comp;
10931
10932 xmlXPathInit();
10933
10934 pctxt = xmlXPathNewParserContext(str, ctxt);
10935 xmlXPathCompileExpr(pctxt);
10936
10937 if( pctxt->error != XPATH_EXPRESSION_OK )
10938 {
10939 xmlXPathFreeParserContext(pctxt);
10940 return (0);
10941 }
10942
10943 if (*pctxt->cur != 0) {
10944 /*
10945 * aleksey: in some cases this line prints *second* error message
10946 * (see bug #78858) and probably this should be fixed.
10947 * However, we are not sure that all error messages are printed
10948 * out in other places. It's not critical so we leave it as-is for now
10949 */
10950 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10951 comp = NULL;
10952 } else {
10953 comp = pctxt->comp;
10954 pctxt->comp = NULL;
10955 }
10956 xmlXPathFreeParserContext(pctxt);
10957 if (comp != NULL) {
10958 comp->expr = xmlStrdup(str);
10959#ifdef DEBUG_EVAL_COUNTS
10960 comp->string = xmlStrdup(str);
10961 comp->nb = 0;
10962#endif
10963 }
10964 return(comp);
10965}
10966
10967/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010968 * xmlXPathCompile:
10969 * @str: the XPath expression
10970 *
10971 * Compile an XPath expression
10972 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010973 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010974 * the caller has to free the object.
10975 */
10976xmlXPathCompExprPtr
10977xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000010978 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010979}
10980
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010981/**
10982 * xmlXPathCompiledEval:
10983 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010984 * @ctx: the XPath context
10985 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010986 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010987 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010988 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010989 * the caller has to free the object.
10990 */
10991xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010992xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010993 xmlXPathParserContextPtr ctxt;
10994 xmlXPathObjectPtr res, tmp, init = NULL;
10995 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010996#ifndef LIBXML_THREAD_ENABLED
10997 static int reentance = 0;
10998#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010999
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011000 if ((comp == NULL) || (ctx == NULL))
11001 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011002 xmlXPathInit();
11003
11004 CHECK_CONTEXT(ctx)
11005
Daniel Veillard81463942001-10-16 12:34:39 +000011006#ifndef LIBXML_THREAD_ENABLED
11007 reentance++;
11008 if (reentance > 1)
11009 xmlXPathDisableOptimizer = 1;
11010#endif
11011
Daniel Veillardf06307e2001-07-03 10:35:50 +000011012#ifdef DEBUG_EVAL_COUNTS
11013 comp->nb++;
11014 if ((comp->string != NULL) && (comp->nb > 100)) {
11015 fprintf(stderr, "100 x %s\n", comp->string);
11016 comp->nb = 0;
11017 }
11018#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011019 ctxt = xmlXPathCompParserContext(comp, ctx);
11020 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011021
11022 if (ctxt->value == NULL) {
11023 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011024 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011025 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011026 } else {
11027 res = valuePop(ctxt);
11028 }
11029
Daniel Veillardf06307e2001-07-03 10:35:50 +000011030
Owen Taylor3473f882001-02-23 17:55:21 +000011031 do {
11032 tmp = valuePop(ctxt);
11033 if (tmp != NULL) {
11034 if (tmp != init)
11035 stack++;
11036 xmlXPathFreeObject(tmp);
11037 }
11038 } while (tmp != NULL);
11039 if ((stack != 0) && (res != NULL)) {
11040 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011041 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011042 stack);
11043 }
11044 if (ctxt->error != XPATH_EXPRESSION_OK) {
11045 xmlXPathFreeObject(res);
11046 res = NULL;
11047 }
11048
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011049
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011050 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011051 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011052#ifndef LIBXML_THREAD_ENABLED
11053 reentance--;
11054#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011055 return(res);
11056}
11057
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011058/**
11059 * xmlXPathEvalExpr:
11060 * @ctxt: the XPath Parser context
11061 *
11062 * Parse and evaluate an XPath expression in the given context,
11063 * then push the result on the context stack
11064 */
11065void
11066xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
11067 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011068 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011069 xmlXPathRunEval(ctxt);
11070}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011071
11072/**
11073 * xmlXPathEval:
11074 * @str: the XPath expression
11075 * @ctx: the XPath context
11076 *
11077 * Evaluate the XPath Location Path in the given context.
11078 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011079 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011080 * the caller has to free the object.
11081 */
11082xmlXPathObjectPtr
11083xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11084 xmlXPathParserContextPtr ctxt;
11085 xmlXPathObjectPtr res, tmp, init = NULL;
11086 int stack = 0;
11087
11088 xmlXPathInit();
11089
11090 CHECK_CONTEXT(ctx)
11091
11092 ctxt = xmlXPathNewParserContext(str, ctx);
11093 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011094
11095 if (ctxt->value == NULL) {
11096 xmlGenericError(xmlGenericErrorContext,
11097 "xmlXPathEval: evaluation failed\n");
11098 res = NULL;
11099 } else if (*ctxt->cur != 0) {
11100 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11101 res = NULL;
11102 } else {
11103 res = valuePop(ctxt);
11104 }
11105
11106 do {
11107 tmp = valuePop(ctxt);
11108 if (tmp != NULL) {
11109 if (tmp != init)
11110 stack++;
11111 xmlXPathFreeObject(tmp);
11112 }
11113 } while (tmp != NULL);
11114 if ((stack != 0) && (res != NULL)) {
11115 xmlGenericError(xmlGenericErrorContext,
11116 "xmlXPathEval: %d object left on the stack\n",
11117 stack);
11118 }
11119 if (ctxt->error != XPATH_EXPRESSION_OK) {
11120 xmlXPathFreeObject(res);
11121 res = NULL;
11122 }
11123
Owen Taylor3473f882001-02-23 17:55:21 +000011124 xmlXPathFreeParserContext(ctxt);
11125 return(res);
11126}
11127
11128/**
11129 * xmlXPathEvalExpression:
11130 * @str: the XPath expression
11131 * @ctxt: the XPath context
11132 *
11133 * Evaluate the XPath expression in the given context.
11134 *
11135 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11136 * the caller has to free the object.
11137 */
11138xmlXPathObjectPtr
11139xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11140 xmlXPathParserContextPtr pctxt;
11141 xmlXPathObjectPtr res, tmp;
11142 int stack = 0;
11143
11144 xmlXPathInit();
11145
11146 CHECK_CONTEXT(ctxt)
11147
11148 pctxt = xmlXPathNewParserContext(str, ctxt);
11149 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011150
11151 if (*pctxt->cur != 0) {
11152 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11153 res = NULL;
11154 } else {
11155 res = valuePop(pctxt);
11156 }
11157 do {
11158 tmp = valuePop(pctxt);
11159 if (tmp != NULL) {
11160 xmlXPathFreeObject(tmp);
11161 stack++;
11162 }
11163 } while (tmp != NULL);
11164 if ((stack != 0) && (res != NULL)) {
11165 xmlGenericError(xmlGenericErrorContext,
11166 "xmlXPathEvalExpression: %d object left on the stack\n",
11167 stack);
11168 }
11169 xmlXPathFreeParserContext(pctxt);
11170 return(res);
11171}
11172
Daniel Veillard42766c02002-08-22 20:52:17 +000011173/************************************************************************
11174 * *
11175 * Extra functions not pertaining to the XPath spec *
11176 * *
11177 ************************************************************************/
11178/**
11179 * xmlXPathEscapeUriFunction:
11180 * @ctxt: the XPath Parser context
11181 * @nargs: the number of arguments
11182 *
11183 * Implement the escape-uri() XPath function
11184 * string escape-uri(string $str, bool $escape-reserved)
11185 *
11186 * This function applies the URI escaping rules defined in section 2 of [RFC
11187 * 2396] to the string supplied as $uri-part, which typically represents all
11188 * or part of a URI. The effect of the function is to replace any special
11189 * character in the string by an escape sequence of the form %xx%yy...,
11190 * where xxyy... is the hexadecimal representation of the octets used to
11191 * represent the character in UTF-8.
11192 *
11193 * The set of characters that are escaped depends on the setting of the
11194 * boolean argument $escape-reserved.
11195 *
11196 * If $escape-reserved is true, all characters are escaped other than lower
11197 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11198 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11199 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11200 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11201 * A-F).
11202 *
11203 * If $escape-reserved is false, the behavior differs in that characters
11204 * referred to in [RFC 2396] as reserved characters are not escaped. These
11205 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11206 *
11207 * [RFC 2396] does not define whether escaped URIs should use lower case or
11208 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11209 * compared using string comparison functions, this function must always use
11210 * the upper-case letters A-F.
11211 *
11212 * Generally, $escape-reserved should be set to true when escaping a string
11213 * that is to form a single part of a URI, and to false when escaping an
11214 * entire URI or URI reference.
11215 *
11216 * In the case of non-ascii characters, the string is encoded according to
11217 * utf-8 and then converted according to RFC 2396.
11218 *
11219 * Examples
11220 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11221 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11222 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11223 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11224 *
11225 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011226static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011227xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11228 xmlXPathObjectPtr str;
11229 int escape_reserved;
11230 xmlBufferPtr target;
11231 xmlChar *cptr;
11232 xmlChar escape[4];
11233
11234 CHECK_ARITY(2);
11235
11236 escape_reserved = xmlXPathPopBoolean(ctxt);
11237
11238 CAST_TO_STRING;
11239 str = valuePop(ctxt);
11240
11241 target = xmlBufferCreate();
11242
11243 escape[0] = '%';
11244 escape[3] = 0;
11245
11246 if (target) {
11247 for (cptr = str->stringval; *cptr; cptr++) {
11248 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11249 (*cptr >= 'a' && *cptr <= 'z') ||
11250 (*cptr >= '0' && *cptr <= '9') ||
11251 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11252 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11253 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11254 (*cptr == '%' &&
11255 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11256 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11257 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11258 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11259 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11260 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11261 (!escape_reserved &&
11262 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11263 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11264 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11265 *cptr == ','))) {
11266 xmlBufferAdd(target, cptr, 1);
11267 } else {
11268 if ((*cptr >> 4) < 10)
11269 escape[1] = '0' + (*cptr >> 4);
11270 else
11271 escape[1] = 'A' - 10 + (*cptr >> 4);
11272 if ((*cptr & 0xF) < 10)
11273 escape[2] = '0' + (*cptr & 0xF);
11274 else
11275 escape[2] = 'A' - 10 + (*cptr & 0xF);
11276
11277 xmlBufferAdd(target, &escape[0], 3);
11278 }
11279 }
11280 }
11281 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11282 xmlBufferFree(target);
11283 xmlXPathFreeObject(str);
11284}
11285
Owen Taylor3473f882001-02-23 17:55:21 +000011286/**
11287 * xmlXPathRegisterAllFunctions:
11288 * @ctxt: the XPath context
11289 *
11290 * Registers all default XPath functions in this context
11291 */
11292void
11293xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11294{
11295 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11296 xmlXPathBooleanFunction);
11297 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11298 xmlXPathCeilingFunction);
11299 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11300 xmlXPathCountFunction);
11301 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11302 xmlXPathConcatFunction);
11303 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11304 xmlXPathContainsFunction);
11305 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11306 xmlXPathIdFunction);
11307 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11308 xmlXPathFalseFunction);
11309 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11310 xmlXPathFloorFunction);
11311 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11312 xmlXPathLastFunction);
11313 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11314 xmlXPathLangFunction);
11315 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11316 xmlXPathLocalNameFunction);
11317 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11318 xmlXPathNotFunction);
11319 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11320 xmlXPathNameFunction);
11321 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11322 xmlXPathNamespaceURIFunction);
11323 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11324 xmlXPathNormalizeFunction);
11325 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11326 xmlXPathNumberFunction);
11327 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11328 xmlXPathPositionFunction);
11329 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11330 xmlXPathRoundFunction);
11331 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11332 xmlXPathStringFunction);
11333 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11334 xmlXPathStringLengthFunction);
11335 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11336 xmlXPathStartsWithFunction);
11337 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11338 xmlXPathSubstringFunction);
11339 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11340 xmlXPathSubstringBeforeFunction);
11341 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11342 xmlXPathSubstringAfterFunction);
11343 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11344 xmlXPathSumFunction);
11345 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11346 xmlXPathTrueFunction);
11347 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11348 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011349
11350 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11351 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11352 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011353}
11354
11355#endif /* LIBXML_XPATH_ENABLED */