blob: 800849111ed4f5c1104e13b8dc23dc10dc4f8c65 [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
178
179static const char *xmlXPathErrorMessages[] = {
180 "Ok\n",
181 "Number encoding\n",
182 "Unfinished literal\n",
183 "Start of literal\n",
184 "Expected $ for variable reference\n",
185 "Undefined variable\n",
186 "Invalid predicate\n",
187 "Invalid expression\n",
188 "Missing closing curly brace\n",
189 "Unregistered function\n",
190 "Invalid operand\n",
191 "Invalid type\n",
192 "Invalid number of arguments\n",
193 "Invalid context size\n",
194 "Invalid context position\n",
195 "Memory allocation error\n",
196 "Syntax error\n",
197 "Resource error\n",
198 "Sub resource error\n",
199 "Undefined namespace prefix\n",
200 "Encoding error\n",
201 "Char out of XML range\n"
202};
203
204
205/**
206 * xmlXPathErrMemory:
207 * @ctxt: an XPath context
208 * @extra: extra informations
209 *
210 * Handle a redefinition of attribute error
211 */
212static void
213xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
214{
215 if (ctxt != NULL) {
216 if (extra) {
217 xmlChar buf[200];
218
219 xmlStrPrintf(buf, 200,
220 BAD_CAST "Memory allocation failed : %s\n",
221 extra);
222 ctxt->lastError.message = (char *) xmlStrdup(buf);
223 } else {
224 ctxt->lastError.message = (char *)
225 xmlStrdup(BAD_CAST "Memory allocation failed\n");
226 }
227 ctxt->lastError.domain = XML_FROM_XPATH;
228 ctxt->lastError.code = XML_ERR_NO_MEMORY;
229 if (ctxt->error != NULL)
230 ctxt->error(ctxt->userData, &ctxt->lastError);
231 } else {
232 if (extra)
233 __xmlRaiseError(NULL, NULL,
234 NULL, NULL, XML_FROM_XPATH,
235 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
236 extra, NULL, NULL, 0, 0,
237 "Memory allocation failed : %s\n", extra);
238 else
239 __xmlRaiseError(NULL, NULL,
240 NULL, NULL, XML_FROM_XPATH,
241 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
242 NULL, NULL, NULL, 0, 0,
243 "Memory allocation failed\n");
244 }
245}
246
247/**
248 * xmlXPathErrMemory:
249 * @ctxt: an XPath parser context
250 * @extra: extra informations
251 *
252 * Handle a redefinition of attribute error
253 */
254static void
255xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
256{
257 ctxt->error = XPATH_MEMORY_ERROR;
258 if (ctxt == NULL)
259 xmlXPathErrMemory(NULL, extra);
260 else
261 xmlXPathErrMemory(ctxt->context, extra);
262}
263
264/**
265 * xmlXPathErr:
266 * @ctxt: a XPath parser context
267 * @node: the node raising the error
268 * @error: the error code
269 * @msg: message
270 * @str1: extra info
271 * @str2: extra info
272 *
273 * Handle a Relax NG Parsing error
274 */
275void
276xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
277{
278 if (ctxt != NULL)
279 ctxt->error = error;
280 if ((ctxt == NULL) || (ctxt->context == NULL)) {
281 __xmlRaiseError(NULL, NULL,
282 NULL, NULL, XML_FROM_XPATH,
283 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
284 XML_ERR_ERROR, NULL, 0,
285 NULL, NULL, NULL, 0, 0,
286 xmlXPathErrorMessages[error]);
287 return;
288 }
289 ctxt->context->lastError.domain = XML_FROM_XPATH;
290 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
291 XPATH_EXPRESSION_OK;
292 ctxt->context->lastError.level = XML_ERR_FATAL;
293 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
294 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
295 ctxt->context->lastError.node = ctxt->context->debugNode;
296 if (ctxt->context->error != NULL) {
297 ctxt->context->error(ctxt->context->userData,
298 &ctxt->context->lastError);
299 } else {
300 __xmlRaiseError(NULL, NULL,
301 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
302 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
303 XML_ERR_ERROR, NULL, 0,
304 (const char *) ctxt->base, NULL, NULL,
305 ctxt->cur - ctxt->base, 0,
306 xmlXPathErrorMessages[error]);
307 }
308
309}
310
311/**
312 * xmlXPatherror:
313 * @ctxt: the XPath Parser context
314 * @file: the file name
315 * @line: the line number
316 * @no: the error number
317 *
318 * Formats an error message.
319 */
320void
321xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
322 int line ATTRIBUTE_UNUSED, int no) {
323 xmlXPathErr(ctxt, no);
324}
325
326
327/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000328 * *
329 * Parser Types *
330 * *
331 ************************************************************************/
332
333/*
334 * Types are private:
335 */
336
337typedef enum {
338 XPATH_OP_END=0,
339 XPATH_OP_AND,
340 XPATH_OP_OR,
341 XPATH_OP_EQUAL,
342 XPATH_OP_CMP,
343 XPATH_OP_PLUS,
344 XPATH_OP_MULT,
345 XPATH_OP_UNION,
346 XPATH_OP_ROOT,
347 XPATH_OP_NODE,
348 XPATH_OP_RESET,
349 XPATH_OP_COLLECT,
350 XPATH_OP_VALUE,
351 XPATH_OP_VARIABLE,
352 XPATH_OP_FUNCTION,
353 XPATH_OP_ARG,
354 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000355 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000356 XPATH_OP_SORT
357#ifdef LIBXML_XPTR_ENABLED
358 ,XPATH_OP_RANGETO
359#endif
360} xmlXPathOp;
361
362typedef enum {
363 AXIS_ANCESTOR = 1,
364 AXIS_ANCESTOR_OR_SELF,
365 AXIS_ATTRIBUTE,
366 AXIS_CHILD,
367 AXIS_DESCENDANT,
368 AXIS_DESCENDANT_OR_SELF,
369 AXIS_FOLLOWING,
370 AXIS_FOLLOWING_SIBLING,
371 AXIS_NAMESPACE,
372 AXIS_PARENT,
373 AXIS_PRECEDING,
374 AXIS_PRECEDING_SIBLING,
375 AXIS_SELF
376} xmlXPathAxisVal;
377
378typedef enum {
379 NODE_TEST_NONE = 0,
380 NODE_TEST_TYPE = 1,
381 NODE_TEST_PI = 2,
382 NODE_TEST_ALL = 3,
383 NODE_TEST_NS = 4,
384 NODE_TEST_NAME = 5
385} xmlXPathTestVal;
386
387typedef enum {
388 NODE_TYPE_NODE = 0,
389 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
390 NODE_TYPE_TEXT = XML_TEXT_NODE,
391 NODE_TYPE_PI = XML_PI_NODE
392} xmlXPathTypeVal;
393
394
395typedef struct _xmlXPathStepOp xmlXPathStepOp;
396typedef xmlXPathStepOp *xmlXPathStepOpPtr;
397struct _xmlXPathStepOp {
398 xmlXPathOp op;
399 int ch1;
400 int ch2;
401 int value;
402 int value2;
403 int value3;
404 void *value4;
405 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000406 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000407 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000408};
409
410struct _xmlXPathCompExpr {
411 int nbStep;
412 int maxStep;
413 xmlXPathStepOp *steps; /* ops for computation */
414 int last;
Daniel Veillard118aed72002-09-24 14:13:13 +0000415 xmlChar *expr;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000416#ifdef DEBUG_EVAL_COUNTS
417 int nb;
418 xmlChar *string;
419#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000420};
421
422/************************************************************************
423 * *
424 * Parser Type functions *
425 * *
426 ************************************************************************/
427
428/**
429 * xmlXPathNewCompExpr:
430 *
431 * Create a new Xpath component
432 *
433 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
434 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000435static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000436xmlXPathNewCompExpr(void) {
437 xmlXPathCompExprPtr cur;
438
439 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
440 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000441 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000442 return(NULL);
443 }
444 memset(cur, 0, sizeof(xmlXPathCompExpr));
445 cur->maxStep = 10;
446 cur->nbStep = 0;
447 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
448 sizeof(xmlXPathStepOp));
449 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000450 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000451 xmlFree(cur);
452 return(NULL);
453 }
454 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
455 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000456#ifdef DEBUG_EVAL_COUNTS
457 cur->nb = 0;
458#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000459 return(cur);
460}
461
462/**
463 * xmlXPathFreeCompExpr:
464 * @comp: an XPATH comp
465 *
466 * Free up the memory allocated by @comp
467 */
468void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000469xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
470{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000471 xmlXPathStepOpPtr op;
472 int i;
473
474 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000475 return;
476 for (i = 0; i < comp->nbStep; i++) {
477 op = &comp->steps[i];
478 if (op->value4 != NULL) {
479 if (op->op == XPATH_OP_VALUE)
480 xmlXPathFreeObject(op->value4);
481 else
482 xmlFree(op->value4);
483 }
484 if (op->value5 != NULL)
485 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000486 }
487 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000488 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000489 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000490#ifdef DEBUG_EVAL_COUNTS
491 if (comp->string != NULL) {
492 xmlFree(comp->string);
493 }
494#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000495 if (comp->expr != NULL) {
496 xmlFree(comp->expr);
497 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000498
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000499 xmlFree(comp);
500}
501
502/**
503 * xmlXPathCompExprAdd:
504 * @comp: the compiled expression
505 * @ch1: first child index
506 * @ch2: second child index
507 * @op: an op
508 * @value: the first int value
509 * @value2: the second int value
510 * @value3: the third int value
511 * @value4: the first string value
512 * @value5: the second string value
513 *
514 * Add an step to an XPath Compiled Expression
515 *
516 * Returns -1 in case of failure, the index otherwise
517 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000518static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000519xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
520 xmlXPathOp op, int value,
521 int value2, int value3, void *value4, void *value5) {
522 if (comp->nbStep >= comp->maxStep) {
523 xmlXPathStepOp *real;
524
525 comp->maxStep *= 2;
526 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
527 comp->maxStep * sizeof(xmlXPathStepOp));
528 if (real == NULL) {
529 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000530 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000531 return(-1);
532 }
533 comp->steps = real;
534 }
535 comp->last = comp->nbStep;
536 comp->steps[comp->nbStep].ch1 = ch1;
537 comp->steps[comp->nbStep].ch2 = ch2;
538 comp->steps[comp->nbStep].op = op;
539 comp->steps[comp->nbStep].value = value;
540 comp->steps[comp->nbStep].value2 = value2;
541 comp->steps[comp->nbStep].value3 = value3;
542 comp->steps[comp->nbStep].value4 = value4;
543 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000544 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000545 return(comp->nbStep++);
546}
547
Daniel Veillardf06307e2001-07-03 10:35:50 +0000548/**
549 * xmlXPathCompSwap:
550 * @comp: the compiled expression
551 * @op: operation index
552 *
553 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000554 */
555static void
556xmlXPathCompSwap(xmlXPathStepOpPtr op) {
557 int tmp;
558
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000559#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000560 /*
561 * Since this manipulates possibly shared variables, this is
562 * disable if one detects that the library is used in a multithreaded
563 * application
564 */
565 if (xmlXPathDisableOptimizer)
566 return;
567#endif
568
Daniel Veillardf06307e2001-07-03 10:35:50 +0000569 tmp = op->ch1;
570 op->ch1 = op->ch2;
571 op->ch2 = tmp;
572}
573
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000574#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
575 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
576 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000577#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
578 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
579 (op), (val), (val2), (val3), (val4), (val5))
580
581#define PUSH_LEAVE_EXPR(op, val, val2) \
582xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
583
584#define PUSH_UNARY_EXPR(op, ch, val, val2) \
585xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
586
587#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
588xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
589
590/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000591 * *
592 * Debugging related functions *
593 * *
594 ************************************************************************/
595
Owen Taylor3473f882001-02-23 17:55:21 +0000596#define STRANGE \
597 xmlGenericError(xmlGenericErrorContext, \
598 "Internal error at %s:%d\n", \
599 __FILE__, __LINE__);
600
601#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000602static void
603xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000604 int i;
605 char shift[100];
606
607 for (i = 0;((i < depth) && (i < 25));i++)
608 shift[2 * i] = shift[2 * i + 1] = ' ';
609 shift[2 * i] = shift[2 * i + 1] = 0;
610 if (cur == NULL) {
611 fprintf(output, shift);
612 fprintf(output, "Node is NULL !\n");
613 return;
614
615 }
616
617 if ((cur->type == XML_DOCUMENT_NODE) ||
618 (cur->type == XML_HTML_DOCUMENT_NODE)) {
619 fprintf(output, shift);
620 fprintf(output, " /\n");
621 } else if (cur->type == XML_ATTRIBUTE_NODE)
622 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
623 else
624 xmlDebugDumpOneNode(output, cur, depth);
625}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000626static void
627xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000628 xmlNodePtr tmp;
629 int i;
630 char shift[100];
631
632 for (i = 0;((i < depth) && (i < 25));i++)
633 shift[2 * i] = shift[2 * i + 1] = ' ';
634 shift[2 * i] = shift[2 * i + 1] = 0;
635 if (cur == NULL) {
636 fprintf(output, shift);
637 fprintf(output, "Node is NULL !\n");
638 return;
639
640 }
641
642 while (cur != NULL) {
643 tmp = cur;
644 cur = cur->next;
645 xmlDebugDumpOneNode(output, tmp, depth);
646 }
647}
Owen Taylor3473f882001-02-23 17:55:21 +0000648
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000649static void
650xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000651 int i;
652 char shift[100];
653
654 for (i = 0;((i < depth) && (i < 25));i++)
655 shift[2 * i] = shift[2 * i + 1] = ' ';
656 shift[2 * i] = shift[2 * i + 1] = 0;
657
658 if (cur == NULL) {
659 fprintf(output, shift);
660 fprintf(output, "NodeSet is NULL !\n");
661 return;
662
663 }
664
Daniel Veillard911f49a2001-04-07 15:39:35 +0000665 if (cur != NULL) {
666 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
667 for (i = 0;i < cur->nodeNr;i++) {
668 fprintf(output, shift);
669 fprintf(output, "%d", i + 1);
670 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
671 }
Owen Taylor3473f882001-02-23 17:55:21 +0000672 }
673}
674
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000675static void
676xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000677 int i;
678 char shift[100];
679
680 for (i = 0;((i < depth) && (i < 25));i++)
681 shift[2 * i] = shift[2 * i + 1] = ' ';
682 shift[2 * i] = shift[2 * i + 1] = 0;
683
684 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
685 fprintf(output, shift);
686 fprintf(output, "Value Tree is NULL !\n");
687 return;
688
689 }
690
691 fprintf(output, shift);
692 fprintf(output, "%d", i + 1);
693 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
694}
Owen Taylor3473f882001-02-23 17:55:21 +0000695#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000696static void
697xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000698 int i;
699 char shift[100];
700
701 for (i = 0;((i < depth) && (i < 25));i++)
702 shift[2 * i] = shift[2 * i + 1] = ' ';
703 shift[2 * i] = shift[2 * i + 1] = 0;
704
705 if (cur == NULL) {
706 fprintf(output, shift);
707 fprintf(output, "LocationSet is NULL !\n");
708 return;
709
710 }
711
712 for (i = 0;i < cur->locNr;i++) {
713 fprintf(output, shift);
714 fprintf(output, "%d : ", i + 1);
715 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
716 }
717}
Daniel Veillard017b1082001-06-21 11:20:21 +0000718#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000719
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000720/**
721 * xmlXPathDebugDumpObject:
722 * @output: the FILE * to dump the output
723 * @cur: the object to inspect
724 * @depth: indentation level
725 *
726 * Dump the content of the object for debugging purposes
727 */
728void
729xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000730 int i;
731 char shift[100];
732
733 for (i = 0;((i < depth) && (i < 25));i++)
734 shift[2 * i] = shift[2 * i + 1] = ' ';
735 shift[2 * i] = shift[2 * i + 1] = 0;
736
737 fprintf(output, shift);
738
739 if (cur == NULL) {
740 fprintf(output, "Object is empty (NULL)\n");
741 return;
742 }
743 switch(cur->type) {
744 case XPATH_UNDEFINED:
745 fprintf(output, "Object is uninitialized\n");
746 break;
747 case XPATH_NODESET:
748 fprintf(output, "Object is a Node Set :\n");
749 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
750 break;
751 case XPATH_XSLT_TREE:
752 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000753 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000754 break;
755 case XPATH_BOOLEAN:
756 fprintf(output, "Object is a Boolean : ");
757 if (cur->boolval) fprintf(output, "true\n");
758 else fprintf(output, "false\n");
759 break;
760 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000761 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000762 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000763 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000764 break;
765 case -1:
766 fprintf(output, "Object is a number : -Infinity\n");
767 break;
768 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000769 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000770 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000771 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
772 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000773 } else {
774 fprintf(output, "Object is a number : %0g\n", cur->floatval);
775 }
776 }
Owen Taylor3473f882001-02-23 17:55:21 +0000777 break;
778 case XPATH_STRING:
779 fprintf(output, "Object is a string : ");
780 xmlDebugDumpString(output, cur->stringval);
781 fprintf(output, "\n");
782 break;
783 case XPATH_POINT:
784 fprintf(output, "Object is a point : index %d in node", cur->index);
785 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
786 fprintf(output, "\n");
787 break;
788 case XPATH_RANGE:
789 if ((cur->user2 == NULL) ||
790 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
791 fprintf(output, "Object is a collapsed range :\n");
792 fprintf(output, shift);
793 if (cur->index >= 0)
794 fprintf(output, "index %d in ", cur->index);
795 fprintf(output, "node\n");
796 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
797 depth + 1);
798 } else {
799 fprintf(output, "Object is a range :\n");
800 fprintf(output, shift);
801 fprintf(output, "From ");
802 if (cur->index >= 0)
803 fprintf(output, "index %d in ", cur->index);
804 fprintf(output, "node\n");
805 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
806 depth + 1);
807 fprintf(output, shift);
808 fprintf(output, "To ");
809 if (cur->index2 >= 0)
810 fprintf(output, "index %d in ", cur->index2);
811 fprintf(output, "node\n");
812 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
813 depth + 1);
814 fprintf(output, "\n");
815 }
816 break;
817 case XPATH_LOCATIONSET:
818#if defined(LIBXML_XPTR_ENABLED)
819 fprintf(output, "Object is a Location Set:\n");
820 xmlXPathDebugDumpLocationSet(output,
821 (xmlLocationSetPtr) cur->user, depth);
822#endif
823 break;
824 case XPATH_USERS:
825 fprintf(output, "Object is user defined\n");
826 break;
827 }
828}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000829
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000830static void
831xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000832 xmlXPathStepOpPtr op, int depth) {
833 int i;
834 char shift[100];
835
836 for (i = 0;((i < depth) && (i < 25));i++)
837 shift[2 * i] = shift[2 * i + 1] = ' ';
838 shift[2 * i] = shift[2 * i + 1] = 0;
839
840 fprintf(output, shift);
841 if (op == NULL) {
842 fprintf(output, "Step is NULL\n");
843 return;
844 }
845 switch (op->op) {
846 case XPATH_OP_END:
847 fprintf(output, "END"); break;
848 case XPATH_OP_AND:
849 fprintf(output, "AND"); break;
850 case XPATH_OP_OR:
851 fprintf(output, "OR"); break;
852 case XPATH_OP_EQUAL:
853 if (op->value)
854 fprintf(output, "EQUAL =");
855 else
856 fprintf(output, "EQUAL !=");
857 break;
858 case XPATH_OP_CMP:
859 if (op->value)
860 fprintf(output, "CMP <");
861 else
862 fprintf(output, "CMP >");
863 if (!op->value2)
864 fprintf(output, "=");
865 break;
866 case XPATH_OP_PLUS:
867 if (op->value == 0)
868 fprintf(output, "PLUS -");
869 else if (op->value == 1)
870 fprintf(output, "PLUS +");
871 else if (op->value == 2)
872 fprintf(output, "PLUS unary -");
873 else if (op->value == 3)
874 fprintf(output, "PLUS unary - -");
875 break;
876 case XPATH_OP_MULT:
877 if (op->value == 0)
878 fprintf(output, "MULT *");
879 else if (op->value == 1)
880 fprintf(output, "MULT div");
881 else
882 fprintf(output, "MULT mod");
883 break;
884 case XPATH_OP_UNION:
885 fprintf(output, "UNION"); break;
886 case XPATH_OP_ROOT:
887 fprintf(output, "ROOT"); break;
888 case XPATH_OP_NODE:
889 fprintf(output, "NODE"); break;
890 case XPATH_OP_RESET:
891 fprintf(output, "RESET"); break;
892 case XPATH_OP_SORT:
893 fprintf(output, "SORT"); break;
894 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000895 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
896 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
897 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000898 const xmlChar *prefix = op->value4;
899 const xmlChar *name = op->value5;
900
901 fprintf(output, "COLLECT ");
902 switch (axis) {
903 case AXIS_ANCESTOR:
904 fprintf(output, " 'ancestors' "); break;
905 case AXIS_ANCESTOR_OR_SELF:
906 fprintf(output, " 'ancestors-or-self' "); break;
907 case AXIS_ATTRIBUTE:
908 fprintf(output, " 'attributes' "); break;
909 case AXIS_CHILD:
910 fprintf(output, " 'child' "); break;
911 case AXIS_DESCENDANT:
912 fprintf(output, " 'descendant' "); break;
913 case AXIS_DESCENDANT_OR_SELF:
914 fprintf(output, " 'descendant-or-self' "); break;
915 case AXIS_FOLLOWING:
916 fprintf(output, " 'following' "); break;
917 case AXIS_FOLLOWING_SIBLING:
918 fprintf(output, " 'following-siblings' "); break;
919 case AXIS_NAMESPACE:
920 fprintf(output, " 'namespace' "); break;
921 case AXIS_PARENT:
922 fprintf(output, " 'parent' "); break;
923 case AXIS_PRECEDING:
924 fprintf(output, " 'preceding' "); break;
925 case AXIS_PRECEDING_SIBLING:
926 fprintf(output, " 'preceding-sibling' "); break;
927 case AXIS_SELF:
928 fprintf(output, " 'self' "); break;
929 }
930 switch (test) {
931 case NODE_TEST_NONE:
932 fprintf(output, "'none' "); break;
933 case NODE_TEST_TYPE:
934 fprintf(output, "'type' "); break;
935 case NODE_TEST_PI:
936 fprintf(output, "'PI' "); break;
937 case NODE_TEST_ALL:
938 fprintf(output, "'all' "); break;
939 case NODE_TEST_NS:
940 fprintf(output, "'namespace' "); break;
941 case NODE_TEST_NAME:
942 fprintf(output, "'name' "); break;
943 }
944 switch (type) {
945 case NODE_TYPE_NODE:
946 fprintf(output, "'node' "); break;
947 case NODE_TYPE_COMMENT:
948 fprintf(output, "'comment' "); break;
949 case NODE_TYPE_TEXT:
950 fprintf(output, "'text' "); break;
951 case NODE_TYPE_PI:
952 fprintf(output, "'PI' "); break;
953 }
954 if (prefix != NULL)
955 fprintf(output, "%s:", prefix);
956 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +0000957 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000958 break;
959
960 }
961 case XPATH_OP_VALUE: {
962 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
963
964 fprintf(output, "ELEM ");
965 xmlXPathDebugDumpObject(output, object, 0);
966 goto finish;
967 }
968 case XPATH_OP_VARIABLE: {
969 const xmlChar *prefix = op->value5;
970 const xmlChar *name = op->value4;
971
972 if (prefix != NULL)
973 fprintf(output, "VARIABLE %s:%s", prefix, name);
974 else
975 fprintf(output, "VARIABLE %s", name);
976 break;
977 }
978 case XPATH_OP_FUNCTION: {
979 int nbargs = op->value;
980 const xmlChar *prefix = op->value5;
981 const xmlChar *name = op->value4;
982
983 if (prefix != NULL)
984 fprintf(output, "FUNCTION %s:%s(%d args)",
985 prefix, name, nbargs);
986 else
987 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
988 break;
989 }
990 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
991 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000992 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000993#ifdef LIBXML_XPTR_ENABLED
994 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
995#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000996 default:
997 fprintf(output, "UNKNOWN %d\n", op->op); return;
998 }
999 fprintf(output, "\n");
1000finish:
1001 if (op->ch1 >= 0)
1002 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1003 if (op->ch2 >= 0)
1004 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1005}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001006
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001007/**
1008 * xmlXPathDebugDumpCompExpr:
1009 * @output: the FILE * for the output
1010 * @comp: the precompiled XPath expression
1011 * @depth: the indentation level.
1012 *
1013 * Dumps the tree of the compiled XPath expression.
1014 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001015void
1016xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1017 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001018 int i;
1019 char shift[100];
1020
1021 for (i = 0;((i < depth) && (i < 25));i++)
1022 shift[2 * i] = shift[2 * i + 1] = ' ';
1023 shift[2 * i] = shift[2 * i + 1] = 0;
1024
1025 fprintf(output, shift);
1026
1027 if (comp == NULL) {
1028 fprintf(output, "Compiled Expression is NULL\n");
1029 return;
1030 }
1031 fprintf(output, "Compiled Expression : %d elements\n",
1032 comp->nbStep);
1033 i = comp->last;
1034 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1035}
Daniel Veillard017b1082001-06-21 11:20:21 +00001036#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001037
1038/************************************************************************
1039 * *
1040 * Parser stacks related functions and macros *
1041 * *
1042 ************************************************************************/
1043
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001044/**
1045 * valuePop:
1046 * @ctxt: an XPath evaluation context
1047 *
1048 * Pops the top XPath object from the value stack
1049 *
1050 * Returns the XPath object just removed
1051 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001052extern xmlXPathObjectPtr
1053valuePop(xmlXPathParserContextPtr ctxt)
1054{
1055 xmlXPathObjectPtr ret;
1056
1057 if (ctxt->valueNr <= 0)
1058 return (0);
1059 ctxt->valueNr--;
1060 if (ctxt->valueNr > 0)
1061 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1062 else
1063 ctxt->value = NULL;
1064 ret = ctxt->valueTab[ctxt->valueNr];
1065 ctxt->valueTab[ctxt->valueNr] = 0;
1066 return (ret);
1067}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001068/**
1069 * valuePush:
1070 * @ctxt: an XPath evaluation context
1071 * @value: the XPath object
1072 *
1073 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001074 *
1075 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001076 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001077extern int
1078valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1079{
1080 if (ctxt->valueNr >= ctxt->valueMax) {
1081 ctxt->valueMax *= 2;
1082 ctxt->valueTab =
1083 (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1084 ctxt->valueMax *
1085 sizeof(ctxt->valueTab[0]));
1086 if (ctxt->valueTab == NULL) {
1087 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1088 return (0);
1089 }
1090 }
1091 ctxt->valueTab[ctxt->valueNr] = value;
1092 ctxt->value = value;
1093 return (ctxt->valueNr++);
1094}
Owen Taylor3473f882001-02-23 17:55:21 +00001095
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001096/**
1097 * xmlXPathPopBoolean:
1098 * @ctxt: an XPath parser context
1099 *
1100 * Pops a boolean from the stack, handling conversion if needed.
1101 * Check error with #xmlXPathCheckError.
1102 *
1103 * Returns the boolean
1104 */
1105int
1106xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1107 xmlXPathObjectPtr obj;
1108 int ret;
1109
1110 obj = valuePop(ctxt);
1111 if (obj == NULL) {
1112 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1113 return(0);
1114 }
1115 ret = xmlXPathCastToBoolean(obj);
1116 xmlXPathFreeObject(obj);
1117 return(ret);
1118}
1119
1120/**
1121 * xmlXPathPopNumber:
1122 * @ctxt: an XPath parser context
1123 *
1124 * Pops a number from the stack, handling conversion if needed.
1125 * Check error with #xmlXPathCheckError.
1126 *
1127 * Returns the number
1128 */
1129double
1130xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1131 xmlXPathObjectPtr obj;
1132 double ret;
1133
1134 obj = valuePop(ctxt);
1135 if (obj == NULL) {
1136 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1137 return(0);
1138 }
1139 ret = xmlXPathCastToNumber(obj);
1140 xmlXPathFreeObject(obj);
1141 return(ret);
1142}
1143
1144/**
1145 * xmlXPathPopString:
1146 * @ctxt: an XPath parser context
1147 *
1148 * Pops a string from the stack, handling conversion if needed.
1149 * Check error with #xmlXPathCheckError.
1150 *
1151 * Returns the string
1152 */
1153xmlChar *
1154xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1155 xmlXPathObjectPtr obj;
1156 xmlChar * ret;
1157
1158 obj = valuePop(ctxt);
1159 if (obj == NULL) {
1160 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1161 return(NULL);
1162 }
1163 ret = xmlXPathCastToString(obj);
1164 /* TODO: needs refactoring somewhere else */
1165 if (obj->stringval == ret)
1166 obj->stringval = NULL;
1167 xmlXPathFreeObject(obj);
1168 return(ret);
1169}
1170
1171/**
1172 * xmlXPathPopNodeSet:
1173 * @ctxt: an XPath parser context
1174 *
1175 * Pops a node-set from the stack, handling conversion if needed.
1176 * Check error with #xmlXPathCheckError.
1177 *
1178 * Returns the node-set
1179 */
1180xmlNodeSetPtr
1181xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1182 xmlXPathObjectPtr obj;
1183 xmlNodeSetPtr ret;
1184
1185 if (ctxt->value == NULL) {
1186 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1187 return(NULL);
1188 }
1189 if (!xmlXPathStackIsNodeSet(ctxt)) {
1190 xmlXPathSetTypeError(ctxt);
1191 return(NULL);
1192 }
1193 obj = valuePop(ctxt);
1194 ret = obj->nodesetval;
Daniel Veillard9deb2422003-07-28 20:40:59 +00001195 /* to fix memory leak of not clearing obj->user */
1196 if (obj->boolval && obj->user != NULL)
1197 xmlFreeNodeList((xmlNodePtr) obj->user);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001198 xmlXPathFreeNodeSetList(obj);
1199 return(ret);
1200}
1201
1202/**
1203 * xmlXPathPopExternal:
1204 * @ctxt: an XPath parser context
1205 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001206 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001207 * Check error with #xmlXPathCheckError.
1208 *
1209 * Returns the object
1210 */
1211void *
1212xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1213 xmlXPathObjectPtr obj;
1214 void * ret;
1215
1216 if (ctxt->value == NULL) {
1217 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1218 return(NULL);
1219 }
1220 if (ctxt->value->type != XPATH_USERS) {
1221 xmlXPathSetTypeError(ctxt);
1222 return(NULL);
1223 }
1224 obj = valuePop(ctxt);
1225 ret = obj->user;
1226 xmlXPathFreeObject(obj);
1227 return(ret);
1228}
1229
Owen Taylor3473f882001-02-23 17:55:21 +00001230/*
1231 * Macros for accessing the content. Those should be used only by the parser,
1232 * and not exported.
1233 *
1234 * Dirty macros, i.e. one need to make assumption on the context to use them
1235 *
1236 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1237 * CUR returns the current xmlChar value, i.e. a 8 bit value
1238 * in ISO-Latin or UTF-8.
1239 * This should be used internally by the parser
1240 * only to compare to ASCII values otherwise it would break when
1241 * running with UTF-8 encoding.
1242 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1243 * to compare on ASCII based substring.
1244 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1245 * strings within the parser.
1246 * CURRENT Returns the current char value, with the full decoding of
1247 * UTF-8 if we are using this mode. It returns an int.
1248 * NEXT Skip to the next character, this does the proper decoding
1249 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1250 * It returns the pointer to the current xmlChar.
1251 */
1252
1253#define CUR (*ctxt->cur)
1254#define SKIP(val) ctxt->cur += (val)
1255#define NXT(val) ctxt->cur[(val)]
1256#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001257#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1258
1259#define COPY_BUF(l,b,i,v) \
1260 if (l == 1) b[i++] = (xmlChar) v; \
1261 else i += xmlCopyChar(l,&b[i],v)
1262
1263#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001264
1265#define SKIP_BLANKS \
1266 while (IS_BLANK(*(ctxt->cur))) NEXT
1267
1268#define CURRENT (*ctxt->cur)
1269#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1270
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001271
1272#ifndef DBL_DIG
1273#define DBL_DIG 16
1274#endif
1275#ifndef DBL_EPSILON
1276#define DBL_EPSILON 1E-9
1277#endif
1278
1279#define UPPER_DOUBLE 1E9
1280#define LOWER_DOUBLE 1E-5
1281
1282#define INTEGER_DIGITS DBL_DIG
1283#define FRACTION_DIGITS (DBL_DIG + 1)
1284#define EXPONENT_DIGITS (3 + 2)
1285
1286/**
1287 * xmlXPathFormatNumber:
1288 * @number: number to format
1289 * @buffer: output buffer
1290 * @buffersize: size of output buffer
1291 *
1292 * Convert the number into a string representation.
1293 */
1294static void
1295xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1296{
Daniel Veillardcda96922001-08-21 10:56:31 +00001297 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001298 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001299 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001300 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001301 break;
1302 case -1:
1303 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001304 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001305 break;
1306 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001307 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001308 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001309 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001310 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001311 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001312 } else if (number == ((int) number)) {
1313 char work[30];
1314 char *ptr, *cur;
1315 int res, value = (int) number;
1316
1317 ptr = &buffer[0];
1318 if (value < 0) {
1319 *ptr++ = '-';
1320 value = -value;
1321 }
1322 if (value == 0) {
1323 *ptr++ = '0';
1324 } else {
1325 cur = &work[0];
1326 while (value != 0) {
1327 res = value % 10;
1328 value = value / 10;
1329 *cur++ = '0' + res;
1330 }
1331 cur--;
1332 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1333 *ptr++ = *cur--;
1334 }
1335 }
1336 if (ptr - buffer < buffersize) {
1337 *ptr = 0;
1338 } else if (buffersize > 0) {
1339 ptr--;
1340 *ptr = 0;
1341 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001342 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001343 /* 3 is sign, decimal point, and terminating zero */
1344 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1345 int integer_place, fraction_place;
1346 char *ptr;
1347 char *after_fraction;
1348 double absolute_value;
1349 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001350
Bjorn Reese70a9da52001-04-21 16:57:29 +00001351 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001352
Bjorn Reese70a9da52001-04-21 16:57:29 +00001353 /*
1354 * First choose format - scientific or regular floating point.
1355 * In either case, result is in work, and after_fraction points
1356 * just past the fractional part.
1357 */
1358 if ( ((absolute_value > UPPER_DOUBLE) ||
1359 (absolute_value < LOWER_DOUBLE)) &&
1360 (absolute_value != 0.0) ) {
1361 /* Use scientific notation */
1362 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1363 fraction_place = DBL_DIG - 1;
1364 snprintf(work, sizeof(work),"%*.*e",
1365 integer_place, fraction_place, number);
1366 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001367 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001368 else {
1369 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001370 if (absolute_value > 0.0)
1371 integer_place = 1 + (int)log10(absolute_value);
1372 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001373 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001374 fraction_place = (integer_place > 0)
1375 ? DBL_DIG - integer_place
1376 : DBL_DIG;
1377 size = snprintf(work, sizeof(work), "%0.*f",
1378 fraction_place, number);
1379 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001380 }
1381
Bjorn Reese70a9da52001-04-21 16:57:29 +00001382 /* Remove fractional trailing zeroes */
1383 ptr = after_fraction;
1384 while (*(--ptr) == '0')
1385 ;
1386 if (*ptr != '.')
1387 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001388 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001389
1390 /* Finally copy result back to caller */
1391 size = strlen(work) + 1;
1392 if (size > buffersize) {
1393 work[buffersize - 1] = 0;
1394 size = buffersize;
1395 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001396 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001397 }
1398 break;
1399 }
1400}
1401
Owen Taylor3473f882001-02-23 17:55:21 +00001402
1403/************************************************************************
1404 * *
1405 * Routines to handle NodeSets *
1406 * *
1407 ************************************************************************/
1408
1409/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001410 * xmlXPathOrderDocElems:
1411 * @doc: an input document
1412 *
1413 * Call this routine to speed up XPath computation on static documents.
1414 * This stamps all the element nodes with the document order
1415 * Like for line information, the order is kept in the element->content
1416 * field, the value stored is actually - the node number (startting at -1)
1417 * to be able to differenciate from line numbers.
1418 *
1419 * Returns the number of element found in the document or -1 in case
1420 * of error.
1421 */
1422long
1423xmlXPathOrderDocElems(xmlDocPtr doc) {
1424 long count = 0;
1425 xmlNodePtr cur;
1426
1427 if (doc == NULL)
1428 return(-1);
1429 cur = doc->children;
1430 while (cur != NULL) {
1431 if (cur->type == XML_ELEMENT_NODE) {
1432 cur->content = (void *) (-(++count));
1433 if (cur->children != NULL) {
1434 cur = cur->children;
1435 continue;
1436 }
1437 }
1438 if (cur->next != NULL) {
1439 cur = cur->next;
1440 continue;
1441 }
1442 do {
1443 cur = cur->parent;
1444 if (cur == NULL)
1445 break;
1446 if (cur == (xmlNodePtr) doc) {
1447 cur = NULL;
1448 break;
1449 }
1450 if (cur->next != NULL) {
1451 cur = cur->next;
1452 break;
1453 }
1454 } while (cur != NULL);
1455 }
1456 return(count);
1457}
1458
1459/**
Owen Taylor3473f882001-02-23 17:55:21 +00001460 * xmlXPathCmpNodes:
1461 * @node1: the first node
1462 * @node2: the second node
1463 *
1464 * Compare two nodes w.r.t document order
1465 *
1466 * Returns -2 in case of error 1 if first point < second point, 0 if
1467 * that's the same node, -1 otherwise
1468 */
1469int
1470xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1471 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001472 int attr1 = 0, attr2 = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001473 xmlNodePtr cur, root;
1474
1475 if ((node1 == NULL) || (node2 == NULL))
1476 return(-2);
1477 /*
1478 * a couple of optimizations which will avoid computations in most cases
1479 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001480 if (node1->type == XML_ATTRIBUTE_NODE) {
1481 attr1 = 1;
1482 node1 = node1->parent;
1483 }
1484 if (node2->type == XML_ATTRIBUTE_NODE) {
1485 attr2 = 1;
1486 node2 = node2->parent;
1487 }
1488 if (node1 == node2) {
1489 if (attr1 == attr2)
1490 return(0);
1491 if (attr2 == 1)
1492 return(1);
1493 return(-1);
1494 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001495 if ((node1->type == XML_NAMESPACE_DECL) ||
1496 (node2->type == XML_NAMESPACE_DECL))
1497 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001498 if (node1 == node2->prev)
1499 return(1);
1500 if (node1 == node2->next)
1501 return(-1);
1502
1503 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001504 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001505 */
1506 if ((node1->type == XML_ELEMENT_NODE) &&
1507 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001508 (0 > (long) node1->content) &&
1509 (0 > (long) node2->content) &&
1510 (node1->doc == node2->doc)) {
1511 long l1, l2;
1512
1513 l1 = -((long) node1->content);
1514 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001515 if (l1 < l2)
1516 return(1);
1517 if (l1 > l2)
1518 return(-1);
1519 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001520
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001521 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001522 * compute depth to root
1523 */
1524 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1525 if (cur == node1)
1526 return(1);
1527 depth2++;
1528 }
1529 root = cur;
1530 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1531 if (cur == node2)
1532 return(-1);
1533 depth1++;
1534 }
1535 /*
1536 * Distinct document (or distinct entities :-( ) case.
1537 */
1538 if (root != cur) {
1539 return(-2);
1540 }
1541 /*
1542 * get the nearest common ancestor.
1543 */
1544 while (depth1 > depth2) {
1545 depth1--;
1546 node1 = node1->parent;
1547 }
1548 while (depth2 > depth1) {
1549 depth2--;
1550 node2 = node2->parent;
1551 }
1552 while (node1->parent != node2->parent) {
1553 node1 = node1->parent;
1554 node2 = node2->parent;
1555 /* should not happen but just in case ... */
1556 if ((node1 == NULL) || (node2 == NULL))
1557 return(-2);
1558 }
1559 /*
1560 * Find who's first.
1561 */
1562 if (node1 == node2->next)
1563 return(-1);
1564 for (cur = node1->next;cur != NULL;cur = cur->next)
1565 if (cur == node2)
1566 return(1);
1567 return(-1); /* assume there is no sibling list corruption */
1568}
1569
1570/**
1571 * xmlXPathNodeSetSort:
1572 * @set: the node set
1573 *
1574 * Sort the node set in document order
1575 */
1576void
1577xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001578 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001579 xmlNodePtr tmp;
1580
1581 if (set == NULL)
1582 return;
1583
1584 /* Use Shell's sort to sort the node-set */
1585 len = set->nodeNr;
1586 for (incr = len / 2; incr > 0; incr /= 2) {
1587 for (i = incr; i < len; i++) {
1588 j = i - incr;
1589 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001590 if (xmlXPathCmpNodes(set->nodeTab[j],
1591 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001592 tmp = set->nodeTab[j];
1593 set->nodeTab[j] = set->nodeTab[j + incr];
1594 set->nodeTab[j + incr] = tmp;
1595 j -= incr;
1596 } else
1597 break;
1598 }
1599 }
1600 }
1601}
1602
1603#define XML_NODESET_DEFAULT 10
1604/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001605 * xmlXPathNodeSetDupNs:
1606 * @node: the parent node of the namespace XPath node
1607 * @ns: the libxml namespace declaration node.
1608 *
1609 * Namespace node in libxml don't match the XPath semantic. In a node set
1610 * the namespace nodes are duplicated and the next pointer is set to the
1611 * parent node in the XPath semantic.
1612 *
1613 * Returns the newly created object.
1614 */
1615static xmlNodePtr
1616xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1617 xmlNsPtr cur;
1618
1619 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1620 return(NULL);
1621 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1622 return((xmlNodePtr) ns);
1623
1624 /*
1625 * Allocate a new Namespace and fill the fields.
1626 */
1627 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1628 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001629 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001630 return(NULL);
1631 }
1632 memset(cur, 0, sizeof(xmlNs));
1633 cur->type = XML_NAMESPACE_DECL;
1634 if (ns->href != NULL)
1635 cur->href = xmlStrdup(ns->href);
1636 if (ns->prefix != NULL)
1637 cur->prefix = xmlStrdup(ns->prefix);
1638 cur->next = (xmlNsPtr) node;
1639 return((xmlNodePtr) cur);
1640}
1641
1642/**
1643 * xmlXPathNodeSetFreeNs:
1644 * @ns: the XPath namespace node found in a nodeset.
1645 *
1646 * Namespace node in libxml don't match the XPath semantic. In a node set
1647 * the namespace nodes are duplicated and the next pointer is set to the
1648 * parent node in the XPath semantic. Check if such a node need to be freed
1649 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001650void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001651xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1652 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1653 return;
1654
1655 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1656 if (ns->href != NULL)
1657 xmlFree((xmlChar *)ns->href);
1658 if (ns->prefix != NULL)
1659 xmlFree((xmlChar *)ns->prefix);
1660 xmlFree(ns);
1661 }
1662}
1663
1664/**
Owen Taylor3473f882001-02-23 17:55:21 +00001665 * xmlXPathNodeSetCreate:
1666 * @val: an initial xmlNodePtr, or NULL
1667 *
1668 * Create a new xmlNodeSetPtr of type double and of value @val
1669 *
1670 * Returns the newly created object.
1671 */
1672xmlNodeSetPtr
1673xmlXPathNodeSetCreate(xmlNodePtr val) {
1674 xmlNodeSetPtr ret;
1675
1676 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1677 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001678 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001679 return(NULL);
1680 }
1681 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1682 if (val != NULL) {
1683 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1684 sizeof(xmlNodePtr));
1685 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001686 xmlXPathErrMemory(NULL, "creating nodeset\n");
1687 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001688 return(NULL);
1689 }
1690 memset(ret->nodeTab, 0 ,
1691 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1692 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001693 if (val->type == XML_NAMESPACE_DECL) {
1694 xmlNsPtr ns = (xmlNsPtr) val;
1695
1696 ret->nodeTab[ret->nodeNr++] =
1697 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1698 } else
1699 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001700 }
1701 return(ret);
1702}
1703
1704/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001705 * xmlXPathNodeSetContains:
1706 * @cur: the node-set
1707 * @val: the node
1708 *
1709 * checks whether @cur contains @val
1710 *
1711 * Returns true (1) if @cur contains @val, false (0) otherwise
1712 */
1713int
1714xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1715 int i;
1716
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001717 if (val->type == XML_NAMESPACE_DECL) {
1718 for (i = 0; i < cur->nodeNr; i++) {
1719 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1720 xmlNsPtr ns1, ns2;
1721
1722 ns1 = (xmlNsPtr) val;
1723 ns2 = (xmlNsPtr) cur->nodeTab[i];
1724 if (ns1 == ns2)
1725 return(1);
1726 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1727 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1728 return(1);
1729 }
1730 }
1731 } else {
1732 for (i = 0; i < cur->nodeNr; i++) {
1733 if (cur->nodeTab[i] == val)
1734 return(1);
1735 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001736 }
1737 return(0);
1738}
1739
1740/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001741 * xmlXPathNodeSetAddNs:
1742 * @cur: the initial node set
1743 * @node: the hosting node
1744 * @ns: a the namespace node
1745 *
1746 * add a new namespace node to an existing NodeSet
1747 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001748void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001749xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1750 int i;
1751
1752 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1753 (node->type != XML_ELEMENT_NODE))
1754 return;
1755
1756 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1757 /*
1758 * check against doublons
1759 */
1760 for (i = 0;i < cur->nodeNr;i++) {
1761 if ((cur->nodeTab[i] != NULL) &&
1762 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001763 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001764 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1765 return;
1766 }
1767
1768 /*
1769 * grow the nodeTab if needed
1770 */
1771 if (cur->nodeMax == 0) {
1772 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1773 sizeof(xmlNodePtr));
1774 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001775 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001776 return;
1777 }
1778 memset(cur->nodeTab, 0 ,
1779 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1780 cur->nodeMax = XML_NODESET_DEFAULT;
1781 } else if (cur->nodeNr == cur->nodeMax) {
1782 xmlNodePtr *temp;
1783
1784 cur->nodeMax *= 2;
1785 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1786 sizeof(xmlNodePtr));
1787 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001788 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001789 return;
1790 }
1791 cur->nodeTab = temp;
1792 }
1793 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1794}
1795
1796/**
Owen Taylor3473f882001-02-23 17:55:21 +00001797 * xmlXPathNodeSetAdd:
1798 * @cur: the initial node set
1799 * @val: a new xmlNodePtr
1800 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001801 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001802 */
1803void
1804xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1805 int i;
1806
1807 if (val == NULL) return;
1808
Daniel Veillardef0b4502003-03-24 13:57:34 +00001809#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001810 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1811 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001812#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001813
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001814 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001815 /*
1816 * check against doublons
1817 */
1818 for (i = 0;i < cur->nodeNr;i++)
1819 if (cur->nodeTab[i] == val) return;
1820
1821 /*
1822 * grow the nodeTab if needed
1823 */
1824 if (cur->nodeMax == 0) {
1825 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1826 sizeof(xmlNodePtr));
1827 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001828 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001829 return;
1830 }
1831 memset(cur->nodeTab, 0 ,
1832 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1833 cur->nodeMax = XML_NODESET_DEFAULT;
1834 } else if (cur->nodeNr == cur->nodeMax) {
1835 xmlNodePtr *temp;
1836
1837 cur->nodeMax *= 2;
1838 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1839 sizeof(xmlNodePtr));
1840 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001841 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001842 return;
1843 }
1844 cur->nodeTab = temp;
1845 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001846 if (val->type == XML_NAMESPACE_DECL) {
1847 xmlNsPtr ns = (xmlNsPtr) val;
1848
1849 cur->nodeTab[cur->nodeNr++] =
1850 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1851 } else
1852 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001853}
1854
1855/**
1856 * xmlXPathNodeSetAddUnique:
1857 * @cur: the initial node set
1858 * @val: a new xmlNodePtr
1859 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001860 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001861 * when we are sure the node is not already in the set.
1862 */
1863void
1864xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1865 if (val == NULL) return;
1866
Daniel Veillardef0b4502003-03-24 13:57:34 +00001867#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001868 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1869 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001870#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001871
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001872 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001873 /*
1874 * grow the nodeTab if needed
1875 */
1876 if (cur->nodeMax == 0) {
1877 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1878 sizeof(xmlNodePtr));
1879 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001880 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001881 return;
1882 }
1883 memset(cur->nodeTab, 0 ,
1884 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1885 cur->nodeMax = XML_NODESET_DEFAULT;
1886 } else if (cur->nodeNr == cur->nodeMax) {
1887 xmlNodePtr *temp;
1888
1889 cur->nodeMax *= 2;
1890 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1891 sizeof(xmlNodePtr));
1892 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001893 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001894 return;
1895 }
1896 cur->nodeTab = temp;
1897 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001898 if (val->type == XML_NAMESPACE_DECL) {
1899 xmlNsPtr ns = (xmlNsPtr) val;
1900
1901 cur->nodeTab[cur->nodeNr++] =
1902 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1903 } else
1904 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001905}
1906
1907/**
1908 * xmlXPathNodeSetMerge:
1909 * @val1: the first NodeSet or NULL
1910 * @val2: the second NodeSet
1911 *
1912 * Merges two nodesets, all nodes from @val2 are added to @val1
1913 * if @val1 is NULL, a new set is created and copied from @val2
1914 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001915 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001916 */
1917xmlNodeSetPtr
1918xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001919 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001920
1921 if (val2 == NULL) return(val1);
1922 if (val1 == NULL) {
1923 val1 = xmlXPathNodeSetCreate(NULL);
1924 }
1925
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001926 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001927 initNr = val1->nodeNr;
1928
1929 for (i = 0;i < val2->nodeNr;i++) {
1930 /*
1931 * check against doublons
1932 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001933 skip = 0;
1934 for (j = 0; j < initNr; j++) {
1935 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1936 skip = 1;
1937 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001938 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1939 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1940 xmlNsPtr ns1, ns2;
1941 ns1 = (xmlNsPtr) val1->nodeTab[j];
1942 ns2 = (xmlNsPtr) val2->nodeTab[i];
1943 if ((ns1->next == ns2->next) &&
1944 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1945 skip = 1;
1946 break;
1947 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001948 }
1949 }
1950 if (skip)
1951 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001952
1953 /*
1954 * grow the nodeTab if needed
1955 */
1956 if (val1->nodeMax == 0) {
1957 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1958 sizeof(xmlNodePtr));
1959 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001960 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001961 return(NULL);
1962 }
1963 memset(val1->nodeTab, 0 ,
1964 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1965 val1->nodeMax = XML_NODESET_DEFAULT;
1966 } else if (val1->nodeNr == val1->nodeMax) {
1967 xmlNodePtr *temp;
1968
1969 val1->nodeMax *= 2;
1970 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1971 sizeof(xmlNodePtr));
1972 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001973 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001974 return(NULL);
1975 }
1976 val1->nodeTab = temp;
1977 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001978 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1979 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1980
1981 val1->nodeTab[val1->nodeNr++] =
1982 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1983 } else
1984 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00001985 }
1986
1987 return(val1);
1988}
1989
1990/**
Daniel Veillard75be0132002-03-13 10:03:35 +00001991 * xmlXPathNodeSetMergeUnique:
1992 * @val1: the first NodeSet or NULL
1993 * @val2: the second NodeSet
1994 *
1995 * Merges two nodesets, all nodes from @val2 are added to @val1
1996 * if @val1 is NULL, a new set is created and copied from @val2
1997 *
1998 * Returns @val1 once extended or NULL in case of error.
1999 */
2000static xmlNodeSetPtr
2001xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002002 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002003
2004 if (val2 == NULL) return(val1);
2005 if (val1 == NULL) {
2006 val1 = xmlXPathNodeSetCreate(NULL);
2007 }
2008
2009 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002010
2011 for (i = 0;i < val2->nodeNr;i++) {
2012 /*
2013 * grow the nodeTab if needed
2014 */
2015 if (val1->nodeMax == 0) {
2016 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2017 sizeof(xmlNodePtr));
2018 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002019 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002020 return(NULL);
2021 }
2022 memset(val1->nodeTab, 0 ,
2023 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2024 val1->nodeMax = XML_NODESET_DEFAULT;
2025 } else if (val1->nodeNr == val1->nodeMax) {
2026 xmlNodePtr *temp;
2027
2028 val1->nodeMax *= 2;
2029 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2030 sizeof(xmlNodePtr));
2031 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002032 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002033 return(NULL);
2034 }
2035 val1->nodeTab = temp;
2036 }
2037 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2038 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2039
2040 val1->nodeTab[val1->nodeNr++] =
2041 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2042 } else
2043 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2044 }
2045
2046 return(val1);
2047}
2048
2049/**
Owen Taylor3473f882001-02-23 17:55:21 +00002050 * xmlXPathNodeSetDel:
2051 * @cur: the initial node set
2052 * @val: an xmlNodePtr
2053 *
2054 * Removes an xmlNodePtr from an existing NodeSet
2055 */
2056void
2057xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2058 int i;
2059
2060 if (cur == NULL) return;
2061 if (val == NULL) return;
2062
2063 /*
2064 * check against doublons
2065 */
2066 for (i = 0;i < cur->nodeNr;i++)
2067 if (cur->nodeTab[i] == val) break;
2068
2069 if (i >= cur->nodeNr) {
2070#ifdef DEBUG
2071 xmlGenericError(xmlGenericErrorContext,
2072 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2073 val->name);
2074#endif
2075 return;
2076 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002077 if ((cur->nodeTab[i] != NULL) &&
2078 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2079 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002080 cur->nodeNr--;
2081 for (;i < cur->nodeNr;i++)
2082 cur->nodeTab[i] = cur->nodeTab[i + 1];
2083 cur->nodeTab[cur->nodeNr] = NULL;
2084}
2085
2086/**
2087 * xmlXPathNodeSetRemove:
2088 * @cur: the initial node set
2089 * @val: the index to remove
2090 *
2091 * Removes an entry from an existing NodeSet list.
2092 */
2093void
2094xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2095 if (cur == NULL) return;
2096 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002097 if ((cur->nodeTab[val] != NULL) &&
2098 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2099 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002100 cur->nodeNr--;
2101 for (;val < cur->nodeNr;val++)
2102 cur->nodeTab[val] = cur->nodeTab[val + 1];
2103 cur->nodeTab[cur->nodeNr] = NULL;
2104}
2105
2106/**
2107 * xmlXPathFreeNodeSet:
2108 * @obj: the xmlNodeSetPtr to free
2109 *
2110 * Free the NodeSet compound (not the actual nodes !).
2111 */
2112void
2113xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2114 if (obj == NULL) return;
2115 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002116 int i;
2117
2118 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
2119 for (i = 0;i < obj->nodeNr;i++)
2120 if ((obj->nodeTab[i] != NULL) &&
2121 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2122 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002123 xmlFree(obj->nodeTab);
2124 }
Owen Taylor3473f882001-02-23 17:55:21 +00002125 xmlFree(obj);
2126}
2127
2128/**
2129 * xmlXPathFreeValueTree:
2130 * @obj: the xmlNodeSetPtr to free
2131 *
2132 * Free the NodeSet compound and the actual tree, this is different
2133 * from xmlXPathFreeNodeSet()
2134 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002135static void
Owen Taylor3473f882001-02-23 17:55:21 +00002136xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2137 int i;
2138
2139 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002140
2141 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002142 for (i = 0;i < obj->nodeNr;i++) {
2143 if (obj->nodeTab[i] != NULL) {
2144 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2145 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2146 } else {
2147 xmlFreeNodeList(obj->nodeTab[i]);
2148 }
2149 }
2150 }
Owen Taylor3473f882001-02-23 17:55:21 +00002151 xmlFree(obj->nodeTab);
2152 }
Owen Taylor3473f882001-02-23 17:55:21 +00002153 xmlFree(obj);
2154}
2155
2156#if defined(DEBUG) || defined(DEBUG_STEP)
2157/**
2158 * xmlGenericErrorContextNodeSet:
2159 * @output: a FILE * for the output
2160 * @obj: the xmlNodeSetPtr to free
2161 *
2162 * Quick display of a NodeSet
2163 */
2164void
2165xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2166 int i;
2167
2168 if (output == NULL) output = xmlGenericErrorContext;
2169 if (obj == NULL) {
2170 fprintf(output, "NodeSet == NULL !\n");
2171 return;
2172 }
2173 if (obj->nodeNr == 0) {
2174 fprintf(output, "NodeSet is empty\n");
2175 return;
2176 }
2177 if (obj->nodeTab == NULL) {
2178 fprintf(output, " nodeTab == NULL !\n");
2179 return;
2180 }
2181 for (i = 0; i < obj->nodeNr; i++) {
2182 if (obj->nodeTab[i] == NULL) {
2183 fprintf(output, " NULL !\n");
2184 return;
2185 }
2186 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2187 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2188 fprintf(output, " /");
2189 else if (obj->nodeTab[i]->name == NULL)
2190 fprintf(output, " noname!");
2191 else fprintf(output, " %s", obj->nodeTab[i]->name);
2192 }
2193 fprintf(output, "\n");
2194}
2195#endif
2196
2197/**
2198 * xmlXPathNewNodeSet:
2199 * @val: the NodePtr value
2200 *
2201 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2202 * it with the single Node @val
2203 *
2204 * Returns the newly created object.
2205 */
2206xmlXPathObjectPtr
2207xmlXPathNewNodeSet(xmlNodePtr val) {
2208 xmlXPathObjectPtr ret;
2209
2210 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2211 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002212 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002213 return(NULL);
2214 }
2215 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2216 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002217 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002218 ret->nodesetval = xmlXPathNodeSetCreate(val);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002219 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002220 return(ret);
2221}
2222
2223/**
2224 * xmlXPathNewValueTree:
2225 * @val: the NodePtr value
2226 *
2227 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2228 * it with the tree root @val
2229 *
2230 * Returns the newly created object.
2231 */
2232xmlXPathObjectPtr
2233xmlXPathNewValueTree(xmlNodePtr val) {
2234 xmlXPathObjectPtr ret;
2235
2236 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2237 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002238 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002239 return(NULL);
2240 }
2241 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2242 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002243 ret->boolval = 1;
2244 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002245 ret->nodesetval = xmlXPathNodeSetCreate(val);
2246 return(ret);
2247}
2248
2249/**
2250 * xmlXPathNewNodeSetList:
2251 * @val: an existing NodeSet
2252 *
2253 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2254 * it with the Nodeset @val
2255 *
2256 * Returns the newly created object.
2257 */
2258xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002259xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2260{
Owen Taylor3473f882001-02-23 17:55:21 +00002261 xmlXPathObjectPtr ret;
2262 int i;
2263
2264 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002265 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002266 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002267 ret = xmlXPathNewNodeSet(NULL);
2268 else {
2269 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2270 for (i = 1; i < val->nodeNr; ++i)
2271 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2272 }
Owen Taylor3473f882001-02-23 17:55:21 +00002273
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002274 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002275}
2276
2277/**
2278 * xmlXPathWrapNodeSet:
2279 * @val: the NodePtr value
2280 *
2281 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2282 *
2283 * Returns the newly created object.
2284 */
2285xmlXPathObjectPtr
2286xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2287 xmlXPathObjectPtr ret;
2288
2289 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2290 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002291 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002292 return(NULL);
2293 }
2294 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2295 ret->type = XPATH_NODESET;
2296 ret->nodesetval = val;
2297 return(ret);
2298}
2299
2300/**
2301 * xmlXPathFreeNodeSetList:
2302 * @obj: an existing NodeSetList object
2303 *
2304 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2305 * the list contrary to xmlXPathFreeObject().
2306 */
2307void
2308xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2309 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002310 xmlFree(obj);
2311}
2312
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002313/**
2314 * xmlXPathDifference:
2315 * @nodes1: a node-set
2316 * @nodes2: a node-set
2317 *
2318 * Implements the EXSLT - Sets difference() function:
2319 * node-set set:difference (node-set, node-set)
2320 *
2321 * Returns the difference between the two node sets, or nodes1 if
2322 * nodes2 is empty
2323 */
2324xmlNodeSetPtr
2325xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2326 xmlNodeSetPtr ret;
2327 int i, l1;
2328 xmlNodePtr cur;
2329
2330 if (xmlXPathNodeSetIsEmpty(nodes2))
2331 return(nodes1);
2332
2333 ret = xmlXPathNodeSetCreate(NULL);
2334 if (xmlXPathNodeSetIsEmpty(nodes1))
2335 return(ret);
2336
2337 l1 = xmlXPathNodeSetGetLength(nodes1);
2338
2339 for (i = 0; i < l1; i++) {
2340 cur = xmlXPathNodeSetItem(nodes1, i);
2341 if (!xmlXPathNodeSetContains(nodes2, cur))
2342 xmlXPathNodeSetAddUnique(ret, cur);
2343 }
2344 return(ret);
2345}
2346
2347/**
2348 * xmlXPathIntersection:
2349 * @nodes1: a node-set
2350 * @nodes2: a node-set
2351 *
2352 * Implements the EXSLT - Sets intersection() function:
2353 * node-set set:intersection (node-set, node-set)
2354 *
2355 * Returns a node set comprising the nodes that are within both the
2356 * node sets passed as arguments
2357 */
2358xmlNodeSetPtr
2359xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2360 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2361 int i, l1;
2362 xmlNodePtr cur;
2363
2364 if (xmlXPathNodeSetIsEmpty(nodes1))
2365 return(ret);
2366 if (xmlXPathNodeSetIsEmpty(nodes2))
2367 return(ret);
2368
2369 l1 = xmlXPathNodeSetGetLength(nodes1);
2370
2371 for (i = 0; i < l1; i++) {
2372 cur = xmlXPathNodeSetItem(nodes1, i);
2373 if (xmlXPathNodeSetContains(nodes2, cur))
2374 xmlXPathNodeSetAddUnique(ret, cur);
2375 }
2376 return(ret);
2377}
2378
2379/**
2380 * xmlXPathDistinctSorted:
2381 * @nodes: a node-set, sorted by document order
2382 *
2383 * Implements the EXSLT - Sets distinct() function:
2384 * node-set set:distinct (node-set)
2385 *
2386 * Returns a subset of the nodes contained in @nodes, or @nodes if
2387 * it is empty
2388 */
2389xmlNodeSetPtr
2390xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2391 xmlNodeSetPtr ret;
2392 xmlHashTablePtr hash;
2393 int i, l;
2394 xmlChar * strval;
2395 xmlNodePtr cur;
2396
2397 if (xmlXPathNodeSetIsEmpty(nodes))
2398 return(nodes);
2399
2400 ret = xmlXPathNodeSetCreate(NULL);
2401 l = xmlXPathNodeSetGetLength(nodes);
2402 hash = xmlHashCreate (l);
2403 for (i = 0; i < l; i++) {
2404 cur = xmlXPathNodeSetItem(nodes, i);
2405 strval = xmlXPathCastNodeToString(cur);
2406 if (xmlHashLookup(hash, strval) == NULL) {
2407 xmlHashAddEntry(hash, strval, strval);
2408 xmlXPathNodeSetAddUnique(ret, cur);
2409 } else {
2410 xmlFree(strval);
2411 }
2412 }
2413 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2414 return(ret);
2415}
2416
2417/**
2418 * xmlXPathDistinct:
2419 * @nodes: a node-set
2420 *
2421 * Implements the EXSLT - Sets distinct() function:
2422 * node-set set:distinct (node-set)
2423 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2424 * is called with the sorted node-set
2425 *
2426 * Returns a subset of the nodes contained in @nodes, or @nodes if
2427 * it is empty
2428 */
2429xmlNodeSetPtr
2430xmlXPathDistinct (xmlNodeSetPtr nodes) {
2431 if (xmlXPathNodeSetIsEmpty(nodes))
2432 return(nodes);
2433
2434 xmlXPathNodeSetSort(nodes);
2435 return(xmlXPathDistinctSorted(nodes));
2436}
2437
2438/**
2439 * xmlXPathHasSameNodes:
2440 * @nodes1: a node-set
2441 * @nodes2: a node-set
2442 *
2443 * Implements the EXSLT - Sets has-same-nodes function:
2444 * boolean set:has-same-node(node-set, node-set)
2445 *
2446 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2447 * otherwise
2448 */
2449int
2450xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2451 int i, l;
2452 xmlNodePtr cur;
2453
2454 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2455 xmlXPathNodeSetIsEmpty(nodes2))
2456 return(0);
2457
2458 l = xmlXPathNodeSetGetLength(nodes1);
2459 for (i = 0; i < l; i++) {
2460 cur = xmlXPathNodeSetItem(nodes1, i);
2461 if (xmlXPathNodeSetContains(nodes2, cur))
2462 return(1);
2463 }
2464 return(0);
2465}
2466
2467/**
2468 * xmlXPathNodeLeadingSorted:
2469 * @nodes: a node-set, sorted by document order
2470 * @node: a node
2471 *
2472 * Implements the EXSLT - Sets leading() function:
2473 * node-set set:leading (node-set, node-set)
2474 *
2475 * Returns the nodes in @nodes that precede @node in document order,
2476 * @nodes if @node is NULL or an empty node-set if @nodes
2477 * doesn't contain @node
2478 */
2479xmlNodeSetPtr
2480xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2481 int i, l;
2482 xmlNodePtr cur;
2483 xmlNodeSetPtr ret;
2484
2485 if (node == NULL)
2486 return(nodes);
2487
2488 ret = xmlXPathNodeSetCreate(NULL);
2489 if (xmlXPathNodeSetIsEmpty(nodes) ||
2490 (!xmlXPathNodeSetContains(nodes, node)))
2491 return(ret);
2492
2493 l = xmlXPathNodeSetGetLength(nodes);
2494 for (i = 0; i < l; i++) {
2495 cur = xmlXPathNodeSetItem(nodes, i);
2496 if (cur == node)
2497 break;
2498 xmlXPathNodeSetAddUnique(ret, cur);
2499 }
2500 return(ret);
2501}
2502
2503/**
2504 * xmlXPathNodeLeading:
2505 * @nodes: a node-set
2506 * @node: a node
2507 *
2508 * Implements the EXSLT - Sets leading() function:
2509 * node-set set:leading (node-set, node-set)
2510 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2511 * is called.
2512 *
2513 * Returns the nodes in @nodes that precede @node in document order,
2514 * @nodes if @node is NULL or an empty node-set if @nodes
2515 * doesn't contain @node
2516 */
2517xmlNodeSetPtr
2518xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2519 xmlXPathNodeSetSort(nodes);
2520 return(xmlXPathNodeLeadingSorted(nodes, node));
2521}
2522
2523/**
2524 * xmlXPathLeadingSorted:
2525 * @nodes1: a node-set, sorted by document order
2526 * @nodes2: a node-set, sorted by document order
2527 *
2528 * Implements the EXSLT - Sets leading() function:
2529 * node-set set:leading (node-set, node-set)
2530 *
2531 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2532 * in document order, @nodes1 if @nodes2 is NULL or empty or
2533 * an empty node-set if @nodes1 doesn't contain @nodes2
2534 */
2535xmlNodeSetPtr
2536xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2537 if (xmlXPathNodeSetIsEmpty(nodes2))
2538 return(nodes1);
2539 return(xmlXPathNodeLeadingSorted(nodes1,
2540 xmlXPathNodeSetItem(nodes2, 1)));
2541}
2542
2543/**
2544 * xmlXPathLeading:
2545 * @nodes1: a node-set
2546 * @nodes2: a node-set
2547 *
2548 * Implements the EXSLT - Sets leading() function:
2549 * node-set set:leading (node-set, node-set)
2550 * @nodes1 and @nodes2 are sorted by document order, then
2551 * #exslSetsLeadingSorted is called.
2552 *
2553 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2554 * in document order, @nodes1 if @nodes2 is NULL or empty or
2555 * an empty node-set if @nodes1 doesn't contain @nodes2
2556 */
2557xmlNodeSetPtr
2558xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2559 if (xmlXPathNodeSetIsEmpty(nodes2))
2560 return(nodes1);
2561 if (xmlXPathNodeSetIsEmpty(nodes1))
2562 return(xmlXPathNodeSetCreate(NULL));
2563 xmlXPathNodeSetSort(nodes1);
2564 xmlXPathNodeSetSort(nodes2);
2565 return(xmlXPathNodeLeadingSorted(nodes1,
2566 xmlXPathNodeSetItem(nodes2, 1)));
2567}
2568
2569/**
2570 * xmlXPathNodeTrailingSorted:
2571 * @nodes: a node-set, sorted by document order
2572 * @node: a node
2573 *
2574 * Implements the EXSLT - Sets trailing() function:
2575 * node-set set:trailing (node-set, node-set)
2576 *
2577 * Returns the nodes in @nodes that follow @node in document order,
2578 * @nodes if @node is NULL or an empty node-set if @nodes
2579 * doesn't contain @node
2580 */
2581xmlNodeSetPtr
2582xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2583 int i, l;
2584 xmlNodePtr cur;
2585 xmlNodeSetPtr ret;
2586
2587 if (node == NULL)
2588 return(nodes);
2589
2590 ret = xmlXPathNodeSetCreate(NULL);
2591 if (xmlXPathNodeSetIsEmpty(nodes) ||
2592 (!xmlXPathNodeSetContains(nodes, node)))
2593 return(ret);
2594
2595 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002596 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002597 cur = xmlXPathNodeSetItem(nodes, i);
2598 if (cur == node)
2599 break;
2600 xmlXPathNodeSetAddUnique(ret, cur);
2601 }
2602 return(ret);
2603}
2604
2605/**
2606 * xmlXPathNodeTrailing:
2607 * @nodes: a node-set
2608 * @node: a node
2609 *
2610 * Implements the EXSLT - Sets trailing() function:
2611 * node-set set:trailing (node-set, node-set)
2612 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2613 * is called.
2614 *
2615 * Returns the nodes in @nodes that follow @node in document order,
2616 * @nodes if @node is NULL or an empty node-set if @nodes
2617 * doesn't contain @node
2618 */
2619xmlNodeSetPtr
2620xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2621 xmlXPathNodeSetSort(nodes);
2622 return(xmlXPathNodeTrailingSorted(nodes, node));
2623}
2624
2625/**
2626 * xmlXPathTrailingSorted:
2627 * @nodes1: a node-set, sorted by document order
2628 * @nodes2: a node-set, sorted by document order
2629 *
2630 * Implements the EXSLT - Sets trailing() function:
2631 * node-set set:trailing (node-set, node-set)
2632 *
2633 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2634 * in document order, @nodes1 if @nodes2 is NULL or empty or
2635 * an empty node-set if @nodes1 doesn't contain @nodes2
2636 */
2637xmlNodeSetPtr
2638xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2639 if (xmlXPathNodeSetIsEmpty(nodes2))
2640 return(nodes1);
2641 return(xmlXPathNodeTrailingSorted(nodes1,
2642 xmlXPathNodeSetItem(nodes2, 0)));
2643}
2644
2645/**
2646 * xmlXPathTrailing:
2647 * @nodes1: a node-set
2648 * @nodes2: a node-set
2649 *
2650 * Implements the EXSLT - Sets trailing() function:
2651 * node-set set:trailing (node-set, node-set)
2652 * @nodes1 and @nodes2 are sorted by document order, then
2653 * #xmlXPathTrailingSorted is called.
2654 *
2655 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2656 * in document order, @nodes1 if @nodes2 is NULL or empty or
2657 * an empty node-set if @nodes1 doesn't contain @nodes2
2658 */
2659xmlNodeSetPtr
2660xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2661 if (xmlXPathNodeSetIsEmpty(nodes2))
2662 return(nodes1);
2663 if (xmlXPathNodeSetIsEmpty(nodes1))
2664 return(xmlXPathNodeSetCreate(NULL));
2665 xmlXPathNodeSetSort(nodes1);
2666 xmlXPathNodeSetSort(nodes2);
2667 return(xmlXPathNodeTrailingSorted(nodes1,
2668 xmlXPathNodeSetItem(nodes2, 0)));
2669}
2670
Owen Taylor3473f882001-02-23 17:55:21 +00002671/************************************************************************
2672 * *
2673 * Routines to handle extra functions *
2674 * *
2675 ************************************************************************/
2676
2677/**
2678 * xmlXPathRegisterFunc:
2679 * @ctxt: the XPath context
2680 * @name: the function name
2681 * @f: the function implementation or NULL
2682 *
2683 * Register a new function. If @f is NULL it unregisters the function
2684 *
2685 * Returns 0 in case of success, -1 in case of error
2686 */
2687int
2688xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2689 xmlXPathFunction f) {
2690 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2691}
2692
2693/**
2694 * xmlXPathRegisterFuncNS:
2695 * @ctxt: the XPath context
2696 * @name: the function name
2697 * @ns_uri: the function namespace URI
2698 * @f: the function implementation or NULL
2699 *
2700 * Register a new function. If @f is NULL it unregisters the function
2701 *
2702 * Returns 0 in case of success, -1 in case of error
2703 */
2704int
2705xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2706 const xmlChar *ns_uri, xmlXPathFunction f) {
2707 if (ctxt == NULL)
2708 return(-1);
2709 if (name == NULL)
2710 return(-1);
2711
2712 if (ctxt->funcHash == NULL)
2713 ctxt->funcHash = xmlHashCreate(0);
2714 if (ctxt->funcHash == NULL)
2715 return(-1);
2716 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2717}
2718
2719/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002720 * xmlXPathRegisterFuncLookup:
2721 * @ctxt: the XPath context
2722 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002723 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002724 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002725 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002726 */
2727void
2728xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2729 xmlXPathFuncLookupFunc f,
2730 void *funcCtxt) {
2731 if (ctxt == NULL)
2732 return;
2733 ctxt->funcLookupFunc = (void *) f;
2734 ctxt->funcLookupData = funcCtxt;
2735}
2736
2737/**
Owen Taylor3473f882001-02-23 17:55:21 +00002738 * xmlXPathFunctionLookup:
2739 * @ctxt: the XPath context
2740 * @name: the function name
2741 *
2742 * Search in the Function array of the context for the given
2743 * function.
2744 *
2745 * Returns the xmlXPathFunction or NULL if not found
2746 */
2747xmlXPathFunction
2748xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002749 if (ctxt == NULL)
2750 return (NULL);
2751
2752 if (ctxt->funcLookupFunc != NULL) {
2753 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002754 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002755
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002756 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002757 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002758 if (ret != NULL)
2759 return(ret);
2760 }
Owen Taylor3473f882001-02-23 17:55:21 +00002761 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2762}
2763
2764/**
2765 * xmlXPathFunctionLookupNS:
2766 * @ctxt: the XPath context
2767 * @name: the function name
2768 * @ns_uri: the function namespace URI
2769 *
2770 * Search in the Function array of the context for the given
2771 * function.
2772 *
2773 * Returns the xmlXPathFunction or NULL if not found
2774 */
2775xmlXPathFunction
2776xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2777 const xmlChar *ns_uri) {
2778 if (ctxt == NULL)
2779 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002780 if (name == NULL)
2781 return(NULL);
2782
Thomas Broyerba4ad322001-07-26 16:55:21 +00002783 if (ctxt->funcLookupFunc != NULL) {
2784 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002785 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002786
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002787 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002788 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002789 if (ret != NULL)
2790 return(ret);
2791 }
2792
2793 if (ctxt->funcHash == NULL)
2794 return(NULL);
2795
Owen Taylor3473f882001-02-23 17:55:21 +00002796 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2797}
2798
2799/**
2800 * xmlXPathRegisteredFuncsCleanup:
2801 * @ctxt: the XPath context
2802 *
2803 * Cleanup the XPath context data associated to registered functions
2804 */
2805void
2806xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2807 if (ctxt == NULL)
2808 return;
2809
2810 xmlHashFree(ctxt->funcHash, NULL);
2811 ctxt->funcHash = NULL;
2812}
2813
2814/************************************************************************
2815 * *
2816 * Routines to handle Variable *
2817 * *
2818 ************************************************************************/
2819
2820/**
2821 * xmlXPathRegisterVariable:
2822 * @ctxt: the XPath context
2823 * @name: the variable name
2824 * @value: the variable value or NULL
2825 *
2826 * Register a new variable value. If @value is NULL it unregisters
2827 * the variable
2828 *
2829 * Returns 0 in case of success, -1 in case of error
2830 */
2831int
2832xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2833 xmlXPathObjectPtr value) {
2834 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2835}
2836
2837/**
2838 * xmlXPathRegisterVariableNS:
2839 * @ctxt: the XPath context
2840 * @name: the variable name
2841 * @ns_uri: the variable namespace URI
2842 * @value: the variable value or NULL
2843 *
2844 * Register a new variable value. If @value is NULL it unregisters
2845 * the variable
2846 *
2847 * Returns 0 in case of success, -1 in case of error
2848 */
2849int
2850xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2851 const xmlChar *ns_uri,
2852 xmlXPathObjectPtr value) {
2853 if (ctxt == NULL)
2854 return(-1);
2855 if (name == NULL)
2856 return(-1);
2857
2858 if (ctxt->varHash == NULL)
2859 ctxt->varHash = xmlHashCreate(0);
2860 if (ctxt->varHash == NULL)
2861 return(-1);
2862 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2863 (void *) value,
2864 (xmlHashDeallocator)xmlXPathFreeObject));
2865}
2866
2867/**
2868 * xmlXPathRegisterVariableLookup:
2869 * @ctxt: the XPath context
2870 * @f: the lookup function
2871 * @data: the lookup data
2872 *
2873 * register an external mechanism to do variable lookup
2874 */
2875void
2876xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2877 xmlXPathVariableLookupFunc f, void *data) {
2878 if (ctxt == NULL)
2879 return;
2880 ctxt->varLookupFunc = (void *) f;
2881 ctxt->varLookupData = data;
2882}
2883
2884/**
2885 * xmlXPathVariableLookup:
2886 * @ctxt: the XPath context
2887 * @name: the variable name
2888 *
2889 * Search in the Variable array of the context for the given
2890 * variable value.
2891 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002892 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002893 */
2894xmlXPathObjectPtr
2895xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2896 if (ctxt == NULL)
2897 return(NULL);
2898
2899 if (ctxt->varLookupFunc != NULL) {
2900 xmlXPathObjectPtr ret;
2901
2902 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2903 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002904 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002905 }
2906 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2907}
2908
2909/**
2910 * xmlXPathVariableLookupNS:
2911 * @ctxt: the XPath context
2912 * @name: the variable name
2913 * @ns_uri: the variable namespace URI
2914 *
2915 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002916 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002917 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002918 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002919 */
2920xmlXPathObjectPtr
2921xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2922 const xmlChar *ns_uri) {
2923 if (ctxt == NULL)
2924 return(NULL);
2925
2926 if (ctxt->varLookupFunc != NULL) {
2927 xmlXPathObjectPtr ret;
2928
2929 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2930 (ctxt->varLookupData, name, ns_uri);
2931 if (ret != NULL) return(ret);
2932 }
2933
2934 if (ctxt->varHash == NULL)
2935 return(NULL);
2936 if (name == NULL)
2937 return(NULL);
2938
Daniel Veillard8c357d52001-07-03 23:43:33 +00002939 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2940 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002941}
2942
2943/**
2944 * xmlXPathRegisteredVariablesCleanup:
2945 * @ctxt: the XPath context
2946 *
2947 * Cleanup the XPath context data associated to registered variables
2948 */
2949void
2950xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2951 if (ctxt == NULL)
2952 return;
2953
Daniel Veillard76d66f42001-05-16 21:05:17 +00002954 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002955 ctxt->varHash = NULL;
2956}
2957
2958/**
2959 * xmlXPathRegisterNs:
2960 * @ctxt: the XPath context
2961 * @prefix: the namespace prefix
2962 * @ns_uri: the namespace name
2963 *
2964 * Register a new namespace. If @ns_uri is NULL it unregisters
2965 * the namespace
2966 *
2967 * Returns 0 in case of success, -1 in case of error
2968 */
2969int
2970xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2971 const xmlChar *ns_uri) {
2972 if (ctxt == NULL)
2973 return(-1);
2974 if (prefix == NULL)
2975 return(-1);
2976
2977 if (ctxt->nsHash == NULL)
2978 ctxt->nsHash = xmlHashCreate(10);
2979 if (ctxt->nsHash == NULL)
2980 return(-1);
Daniel Veillard42766c02002-08-22 20:52:17 +00002981 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00002982 (xmlHashDeallocator)xmlFree));
2983}
2984
2985/**
2986 * xmlXPathNsLookup:
2987 * @ctxt: the XPath context
2988 * @prefix: the namespace prefix value
2989 *
2990 * Search in the namespace declaration array of the context for the given
2991 * namespace name associated to the given prefix
2992 *
2993 * Returns the value or NULL if not found
2994 */
2995const xmlChar *
2996xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2997 if (ctxt == NULL)
2998 return(NULL);
2999 if (prefix == NULL)
3000 return(NULL);
3001
3002#ifdef XML_XML_NAMESPACE
3003 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3004 return(XML_XML_NAMESPACE);
3005#endif
3006
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003007 if (ctxt->namespaces != NULL) {
3008 int i;
3009
3010 for (i = 0;i < ctxt->nsNr;i++) {
3011 if ((ctxt->namespaces[i] != NULL) &&
3012 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3013 return(ctxt->namespaces[i]->href);
3014 }
3015 }
Owen Taylor3473f882001-02-23 17:55:21 +00003016
3017 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3018}
3019
3020/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003021 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003022 * @ctxt: the XPath context
3023 *
3024 * Cleanup the XPath context data associated to registered variables
3025 */
3026void
3027xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3028 if (ctxt == NULL)
3029 return;
3030
Daniel Veillard42766c02002-08-22 20:52:17 +00003031 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003032 ctxt->nsHash = NULL;
3033}
3034
3035/************************************************************************
3036 * *
3037 * Routines to handle Values *
3038 * *
3039 ************************************************************************/
3040
3041/* Allocations are terrible, one need to optimize all this !!! */
3042
3043/**
3044 * xmlXPathNewFloat:
3045 * @val: the double value
3046 *
3047 * Create a new xmlXPathObjectPtr of type double and of value @val
3048 *
3049 * Returns the newly created object.
3050 */
3051xmlXPathObjectPtr
3052xmlXPathNewFloat(double val) {
3053 xmlXPathObjectPtr ret;
3054
3055 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3056 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003057 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003058 return(NULL);
3059 }
3060 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3061 ret->type = XPATH_NUMBER;
3062 ret->floatval = val;
3063 return(ret);
3064}
3065
3066/**
3067 * xmlXPathNewBoolean:
3068 * @val: the boolean value
3069 *
3070 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3071 *
3072 * Returns the newly created object.
3073 */
3074xmlXPathObjectPtr
3075xmlXPathNewBoolean(int val) {
3076 xmlXPathObjectPtr ret;
3077
3078 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3079 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003080 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003081 return(NULL);
3082 }
3083 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3084 ret->type = XPATH_BOOLEAN;
3085 ret->boolval = (val != 0);
3086 return(ret);
3087}
3088
3089/**
3090 * xmlXPathNewString:
3091 * @val: the xmlChar * value
3092 *
3093 * Create a new xmlXPathObjectPtr of type string and of value @val
3094 *
3095 * Returns the newly created object.
3096 */
3097xmlXPathObjectPtr
3098xmlXPathNewString(const xmlChar *val) {
3099 xmlXPathObjectPtr ret;
3100
3101 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3102 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003103 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003104 return(NULL);
3105 }
3106 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3107 ret->type = XPATH_STRING;
3108 if (val != NULL)
3109 ret->stringval = xmlStrdup(val);
3110 else
3111 ret->stringval = xmlStrdup((const xmlChar *)"");
3112 return(ret);
3113}
3114
3115/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003116 * xmlXPathWrapString:
3117 * @val: the xmlChar * value
3118 *
3119 * Wraps the @val string into an XPath object.
3120 *
3121 * Returns the newly created object.
3122 */
3123xmlXPathObjectPtr
3124xmlXPathWrapString (xmlChar *val) {
3125 xmlXPathObjectPtr ret;
3126
3127 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3128 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003129 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003130 return(NULL);
3131 }
3132 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3133 ret->type = XPATH_STRING;
3134 ret->stringval = val;
3135 return(ret);
3136}
3137
3138/**
Owen Taylor3473f882001-02-23 17:55:21 +00003139 * xmlXPathNewCString:
3140 * @val: the char * value
3141 *
3142 * Create a new xmlXPathObjectPtr of type string and of value @val
3143 *
3144 * Returns the newly created object.
3145 */
3146xmlXPathObjectPtr
3147xmlXPathNewCString(const char *val) {
3148 xmlXPathObjectPtr ret;
3149
3150 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3151 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003152 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003153 return(NULL);
3154 }
3155 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3156 ret->type = XPATH_STRING;
3157 ret->stringval = xmlStrdup(BAD_CAST val);
3158 return(ret);
3159}
3160
3161/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003162 * xmlXPathWrapCString:
3163 * @val: the char * value
3164 *
3165 * Wraps a string into an XPath object.
3166 *
3167 * Returns the newly created object.
3168 */
3169xmlXPathObjectPtr
3170xmlXPathWrapCString (char * val) {
3171 return(xmlXPathWrapString((xmlChar *)(val)));
3172}
3173
3174/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003175 * xmlXPathWrapExternal:
3176 * @val: the user data
3177 *
3178 * Wraps the @val data into an XPath object.
3179 *
3180 * Returns the newly created object.
3181 */
3182xmlXPathObjectPtr
3183xmlXPathWrapExternal (void *val) {
3184 xmlXPathObjectPtr ret;
3185
3186 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3187 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003188 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003189 return(NULL);
3190 }
3191 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3192 ret->type = XPATH_USERS;
3193 ret->user = val;
3194 return(ret);
3195}
3196
3197/**
Owen Taylor3473f882001-02-23 17:55:21 +00003198 * xmlXPathObjectCopy:
3199 * @val: the original object
3200 *
3201 * allocate a new copy of a given object
3202 *
3203 * Returns the newly created object.
3204 */
3205xmlXPathObjectPtr
3206xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3207 xmlXPathObjectPtr ret;
3208
3209 if (val == NULL)
3210 return(NULL);
3211
3212 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3213 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003214 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003215 return(NULL);
3216 }
3217 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3218 switch (val->type) {
3219 case XPATH_BOOLEAN:
3220 case XPATH_NUMBER:
3221 case XPATH_POINT:
3222 case XPATH_RANGE:
3223 break;
3224 case XPATH_STRING:
3225 ret->stringval = xmlStrdup(val->stringval);
3226 break;
3227 case XPATH_XSLT_TREE:
3228 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003229 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003230 xmlNodePtr cur, tmp;
3231 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003232
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003233 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003234 top = xmlNewDoc(NULL);
3235 top->name = (char *)
3236 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003237 ret->user = top;
3238 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003239 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003240 cur = val->nodesetval->nodeTab[0]->children;
3241 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003242 tmp = xmlDocCopyNode(cur, top, 1);
3243 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003244 cur = cur->next;
3245 }
3246 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003247 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003248 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003249 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003250 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003251 break;
3252 case XPATH_NODESET:
3253 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003254 /* Do not deallocate the copied tree value */
3255 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003256 break;
3257 case XPATH_LOCATIONSET:
3258#ifdef LIBXML_XPTR_ENABLED
3259 {
3260 xmlLocationSetPtr loc = val->user;
3261 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3262 break;
3263 }
3264#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003265 case XPATH_USERS:
3266 ret->user = val->user;
3267 break;
3268 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003269 xmlGenericError(xmlGenericErrorContext,
3270 "xmlXPathObjectCopy: unsupported type %d\n",
3271 val->type);
3272 break;
3273 }
3274 return(ret);
3275}
3276
3277/**
3278 * xmlXPathFreeObject:
3279 * @obj: the object to free
3280 *
3281 * Free up an xmlXPathObjectPtr object.
3282 */
3283void
3284xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3285 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003286 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003287 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003288 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003289 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003290 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003291 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003292 xmlXPathFreeValueTree(obj->nodesetval);
3293 } else {
3294 if (obj->nodesetval != NULL)
3295 xmlXPathFreeNodeSet(obj->nodesetval);
3296 }
Owen Taylor3473f882001-02-23 17:55:21 +00003297#ifdef LIBXML_XPTR_ENABLED
3298 } else if (obj->type == XPATH_LOCATIONSET) {
3299 if (obj->user != NULL)
3300 xmlXPtrFreeLocationSet(obj->user);
3301#endif
3302 } else if (obj->type == XPATH_STRING) {
3303 if (obj->stringval != NULL)
3304 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003305 }
3306
Owen Taylor3473f882001-02-23 17:55:21 +00003307 xmlFree(obj);
3308}
3309
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003310
3311/************************************************************************
3312 * *
3313 * Type Casting Routines *
3314 * *
3315 ************************************************************************/
3316
3317/**
3318 * xmlXPathCastBooleanToString:
3319 * @val: a boolean
3320 *
3321 * Converts a boolean to its string value.
3322 *
3323 * Returns a newly allocated string.
3324 */
3325xmlChar *
3326xmlXPathCastBooleanToString (int val) {
3327 xmlChar *ret;
3328 if (val)
3329 ret = xmlStrdup((const xmlChar *) "true");
3330 else
3331 ret = xmlStrdup((const xmlChar *) "false");
3332 return(ret);
3333}
3334
3335/**
3336 * xmlXPathCastNumberToString:
3337 * @val: a number
3338 *
3339 * Converts a number to its string value.
3340 *
3341 * Returns a newly allocated string.
3342 */
3343xmlChar *
3344xmlXPathCastNumberToString (double val) {
3345 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003346 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003347 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003348 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003349 break;
3350 case -1:
3351 ret = xmlStrdup((const xmlChar *) "-Infinity");
3352 break;
3353 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003354 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003355 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003356 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3357 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003358 } else {
3359 /* could be improved */
3360 char buf[100];
3361 xmlXPathFormatNumber(val, buf, 100);
3362 ret = xmlStrdup((const xmlChar *) buf);
3363 }
3364 }
3365 return(ret);
3366}
3367
3368/**
3369 * xmlXPathCastNodeToString:
3370 * @node: a node
3371 *
3372 * Converts a node to its string value.
3373 *
3374 * Returns a newly allocated string.
3375 */
3376xmlChar *
3377xmlXPathCastNodeToString (xmlNodePtr node) {
3378 return(xmlNodeGetContent(node));
3379}
3380
3381/**
3382 * xmlXPathCastNodeSetToString:
3383 * @ns: a node-set
3384 *
3385 * Converts a node-set to its string value.
3386 *
3387 * Returns a newly allocated string.
3388 */
3389xmlChar *
3390xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3391 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3392 return(xmlStrdup((const xmlChar *) ""));
3393
3394 xmlXPathNodeSetSort(ns);
3395 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3396}
3397
3398/**
3399 * xmlXPathCastToString:
3400 * @val: an XPath object
3401 *
3402 * Converts an existing object to its string() equivalent
3403 *
3404 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003405 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003406 * string object).
3407 */
3408xmlChar *
3409xmlXPathCastToString(xmlXPathObjectPtr val) {
3410 xmlChar *ret = NULL;
3411
3412 if (val == NULL)
3413 return(xmlStrdup((const xmlChar *) ""));
3414 switch (val->type) {
3415 case XPATH_UNDEFINED:
3416#ifdef DEBUG_EXPR
3417 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3418#endif
3419 ret = xmlStrdup((const xmlChar *) "");
3420 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003421 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003422 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003423 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3424 break;
3425 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003426 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003427 case XPATH_BOOLEAN:
3428 ret = xmlXPathCastBooleanToString(val->boolval);
3429 break;
3430 case XPATH_NUMBER: {
3431 ret = xmlXPathCastNumberToString(val->floatval);
3432 break;
3433 }
3434 case XPATH_USERS:
3435 case XPATH_POINT:
3436 case XPATH_RANGE:
3437 case XPATH_LOCATIONSET:
3438 TODO
3439 ret = xmlStrdup((const xmlChar *) "");
3440 break;
3441 }
3442 return(ret);
3443}
3444
3445/**
3446 * xmlXPathConvertString:
3447 * @val: an XPath object
3448 *
3449 * Converts an existing object to its string() equivalent
3450 *
3451 * Returns the new object, the old one is freed (or the operation
3452 * is done directly on @val)
3453 */
3454xmlXPathObjectPtr
3455xmlXPathConvertString(xmlXPathObjectPtr val) {
3456 xmlChar *res = NULL;
3457
3458 if (val == NULL)
3459 return(xmlXPathNewCString(""));
3460
3461 switch (val->type) {
3462 case XPATH_UNDEFINED:
3463#ifdef DEBUG_EXPR
3464 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3465#endif
3466 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003467 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003468 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003469 res = xmlXPathCastNodeSetToString(val->nodesetval);
3470 break;
3471 case XPATH_STRING:
3472 return(val);
3473 case XPATH_BOOLEAN:
3474 res = xmlXPathCastBooleanToString(val->boolval);
3475 break;
3476 case XPATH_NUMBER:
3477 res = xmlXPathCastNumberToString(val->floatval);
3478 break;
3479 case XPATH_USERS:
3480 case XPATH_POINT:
3481 case XPATH_RANGE:
3482 case XPATH_LOCATIONSET:
3483 TODO;
3484 break;
3485 }
3486 xmlXPathFreeObject(val);
3487 if (res == NULL)
3488 return(xmlXPathNewCString(""));
3489 return(xmlXPathWrapString(res));
3490}
3491
3492/**
3493 * xmlXPathCastBooleanToNumber:
3494 * @val: a boolean
3495 *
3496 * Converts a boolean to its number value
3497 *
3498 * Returns the number value
3499 */
3500double
3501xmlXPathCastBooleanToNumber(int val) {
3502 if (val)
3503 return(1.0);
3504 return(0.0);
3505}
3506
3507/**
3508 * xmlXPathCastStringToNumber:
3509 * @val: a string
3510 *
3511 * Converts a string to its number value
3512 *
3513 * Returns the number value
3514 */
3515double
3516xmlXPathCastStringToNumber(const xmlChar * val) {
3517 return(xmlXPathStringEvalNumber(val));
3518}
3519
3520/**
3521 * xmlXPathCastNodeToNumber:
3522 * @node: a node
3523 *
3524 * Converts a node to its number value
3525 *
3526 * Returns the number value
3527 */
3528double
3529xmlXPathCastNodeToNumber (xmlNodePtr node) {
3530 xmlChar *strval;
3531 double ret;
3532
3533 if (node == NULL)
3534 return(xmlXPathNAN);
3535 strval = xmlXPathCastNodeToString(node);
3536 if (strval == NULL)
3537 return(xmlXPathNAN);
3538 ret = xmlXPathCastStringToNumber(strval);
3539 xmlFree(strval);
3540
3541 return(ret);
3542}
3543
3544/**
3545 * xmlXPathCastNodeSetToNumber:
3546 * @ns: a node-set
3547 *
3548 * Converts a node-set to its number value
3549 *
3550 * Returns the number value
3551 */
3552double
3553xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3554 xmlChar *str;
3555 double ret;
3556
3557 if (ns == NULL)
3558 return(xmlXPathNAN);
3559 str = xmlXPathCastNodeSetToString(ns);
3560 ret = xmlXPathCastStringToNumber(str);
3561 xmlFree(str);
3562 return(ret);
3563}
3564
3565/**
3566 * xmlXPathCastToNumber:
3567 * @val: an XPath object
3568 *
3569 * Converts an XPath object to its number value
3570 *
3571 * Returns the number value
3572 */
3573double
3574xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3575 double ret = 0.0;
3576
3577 if (val == NULL)
3578 return(xmlXPathNAN);
3579 switch (val->type) {
3580 case XPATH_UNDEFINED:
3581#ifdef DEGUB_EXPR
3582 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3583#endif
3584 ret = xmlXPathNAN;
3585 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003586 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003587 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003588 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3589 break;
3590 case XPATH_STRING:
3591 ret = xmlXPathCastStringToNumber(val->stringval);
3592 break;
3593 case XPATH_NUMBER:
3594 ret = val->floatval;
3595 break;
3596 case XPATH_BOOLEAN:
3597 ret = xmlXPathCastBooleanToNumber(val->boolval);
3598 break;
3599 case XPATH_USERS:
3600 case XPATH_POINT:
3601 case XPATH_RANGE:
3602 case XPATH_LOCATIONSET:
3603 TODO;
3604 ret = xmlXPathNAN;
3605 break;
3606 }
3607 return(ret);
3608}
3609
3610/**
3611 * xmlXPathConvertNumber:
3612 * @val: an XPath object
3613 *
3614 * Converts an existing object to its number() equivalent
3615 *
3616 * Returns the new object, the old one is freed (or the operation
3617 * is done directly on @val)
3618 */
3619xmlXPathObjectPtr
3620xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3621 xmlXPathObjectPtr ret;
3622
3623 if (val == NULL)
3624 return(xmlXPathNewFloat(0.0));
3625 if (val->type == XPATH_NUMBER)
3626 return(val);
3627 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3628 xmlXPathFreeObject(val);
3629 return(ret);
3630}
3631
3632/**
3633 * xmlXPathCastNumberToBoolean:
3634 * @val: a number
3635 *
3636 * Converts a number to its boolean value
3637 *
3638 * Returns the boolean value
3639 */
3640int
3641xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003642 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003643 return(0);
3644 return(1);
3645}
3646
3647/**
3648 * xmlXPathCastStringToBoolean:
3649 * @val: a string
3650 *
3651 * Converts a string to its boolean value
3652 *
3653 * Returns the boolean value
3654 */
3655int
3656xmlXPathCastStringToBoolean (const xmlChar *val) {
3657 if ((val == NULL) || (xmlStrlen(val) == 0))
3658 return(0);
3659 return(1);
3660}
3661
3662/**
3663 * xmlXPathCastNodeSetToBoolean:
3664 * @ns: a node-set
3665 *
3666 * Converts a node-set to its boolean value
3667 *
3668 * Returns the boolean value
3669 */
3670int
3671xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3672 if ((ns == NULL) || (ns->nodeNr == 0))
3673 return(0);
3674 return(1);
3675}
3676
3677/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003678 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003679 * @val: an XPath object
3680 *
3681 * Converts an XPath object to its boolean value
3682 *
3683 * Returns the boolean value
3684 */
3685int
3686xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3687 int ret = 0;
3688
3689 if (val == NULL)
3690 return(0);
3691 switch (val->type) {
3692 case XPATH_UNDEFINED:
3693#ifdef DEBUG_EXPR
3694 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3695#endif
3696 ret = 0;
3697 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003698 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003699 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003700 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3701 break;
3702 case XPATH_STRING:
3703 ret = xmlXPathCastStringToBoolean(val->stringval);
3704 break;
3705 case XPATH_NUMBER:
3706 ret = xmlXPathCastNumberToBoolean(val->floatval);
3707 break;
3708 case XPATH_BOOLEAN:
3709 ret = val->boolval;
3710 break;
3711 case XPATH_USERS:
3712 case XPATH_POINT:
3713 case XPATH_RANGE:
3714 case XPATH_LOCATIONSET:
3715 TODO;
3716 ret = 0;
3717 break;
3718 }
3719 return(ret);
3720}
3721
3722
3723/**
3724 * xmlXPathConvertBoolean:
3725 * @val: an XPath object
3726 *
3727 * Converts an existing object to its boolean() equivalent
3728 *
3729 * Returns the new object, the old one is freed (or the operation
3730 * is done directly on @val)
3731 */
3732xmlXPathObjectPtr
3733xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3734 xmlXPathObjectPtr ret;
3735
3736 if (val == NULL)
3737 return(xmlXPathNewBoolean(0));
3738 if (val->type == XPATH_BOOLEAN)
3739 return(val);
3740 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3741 xmlXPathFreeObject(val);
3742 return(ret);
3743}
3744
Owen Taylor3473f882001-02-23 17:55:21 +00003745/************************************************************************
3746 * *
3747 * Routines to handle XPath contexts *
3748 * *
3749 ************************************************************************/
3750
3751/**
3752 * xmlXPathNewContext:
3753 * @doc: the XML document
3754 *
3755 * Create a new xmlXPathContext
3756 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003757 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003758 */
3759xmlXPathContextPtr
3760xmlXPathNewContext(xmlDocPtr doc) {
3761 xmlXPathContextPtr ret;
3762
3763 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3764 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003765 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003766 return(NULL);
3767 }
3768 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3769 ret->doc = doc;
3770 ret->node = NULL;
3771
3772 ret->varHash = NULL;
3773
3774 ret->nb_types = 0;
3775 ret->max_types = 0;
3776 ret->types = NULL;
3777
3778 ret->funcHash = xmlHashCreate(0);
3779
3780 ret->nb_axis = 0;
3781 ret->max_axis = 0;
3782 ret->axis = NULL;
3783
3784 ret->nsHash = NULL;
3785 ret->user = NULL;
3786
3787 ret->contextSize = -1;
3788 ret->proximityPosition = -1;
3789
3790 xmlXPathRegisterAllFunctions(ret);
3791
3792 return(ret);
3793}
3794
3795/**
3796 * xmlXPathFreeContext:
3797 * @ctxt: the context to free
3798 *
3799 * Free up an xmlXPathContext
3800 */
3801void
3802xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3803 xmlXPathRegisteredNsCleanup(ctxt);
3804 xmlXPathRegisteredFuncsCleanup(ctxt);
3805 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003806 xmlFree(ctxt);
3807}
3808
3809/************************************************************************
3810 * *
3811 * Routines to handle XPath parser contexts *
3812 * *
3813 ************************************************************************/
3814
3815#define CHECK_CTXT(ctxt) \
3816 if (ctxt == NULL) { \
3817 xmlGenericError(xmlGenericErrorContext, \
3818 "%s:%d Internal error: ctxt == NULL\n", \
3819 __FILE__, __LINE__); \
3820 } \
3821
3822
3823#define CHECK_CONTEXT(ctxt) \
3824 if (ctxt == NULL) { \
3825 xmlGenericError(xmlGenericErrorContext, \
3826 "%s:%d Internal error: no context\n", \
3827 __FILE__, __LINE__); \
3828 } \
3829 else if (ctxt->doc == NULL) { \
3830 xmlGenericError(xmlGenericErrorContext, \
3831 "%s:%d Internal error: no document\n", \
3832 __FILE__, __LINE__); \
3833 } \
3834 else if (ctxt->doc->children == NULL) { \
3835 xmlGenericError(xmlGenericErrorContext, \
3836 "%s:%d Internal error: document without root\n", \
3837 __FILE__, __LINE__); \
3838 } \
3839
3840
3841/**
3842 * xmlXPathNewParserContext:
3843 * @str: the XPath expression
3844 * @ctxt: the XPath context
3845 *
3846 * Create a new xmlXPathParserContext
3847 *
3848 * Returns the xmlXPathParserContext just allocated.
3849 */
3850xmlXPathParserContextPtr
3851xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3852 xmlXPathParserContextPtr ret;
3853
3854 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3855 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003856 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003857 return(NULL);
3858 }
3859 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3860 ret->cur = ret->base = str;
3861 ret->context = ctxt;
3862
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003863 ret->comp = xmlXPathNewCompExpr();
3864 if (ret->comp == NULL) {
3865 xmlFree(ret->valueTab);
3866 xmlFree(ret);
3867 return(NULL);
3868 }
3869
3870 return(ret);
3871}
3872
3873/**
3874 * xmlXPathCompParserContext:
3875 * @comp: the XPath compiled expression
3876 * @ctxt: the XPath context
3877 *
3878 * Create a new xmlXPathParserContext when processing a compiled expression
3879 *
3880 * Returns the xmlXPathParserContext just allocated.
3881 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003882static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003883xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3884 xmlXPathParserContextPtr ret;
3885
3886 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3887 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003888 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003889 return(NULL);
3890 }
3891 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3892
Owen Taylor3473f882001-02-23 17:55:21 +00003893 /* Allocate the value stack */
3894 ret->valueTab = (xmlXPathObjectPtr *)
3895 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003896 if (ret->valueTab == NULL) {
3897 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003898 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003899 return(NULL);
3900 }
Owen Taylor3473f882001-02-23 17:55:21 +00003901 ret->valueNr = 0;
3902 ret->valueMax = 10;
3903 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003904
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003905 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003906 ret->comp = comp;
3907
Owen Taylor3473f882001-02-23 17:55:21 +00003908 return(ret);
3909}
3910
3911/**
3912 * xmlXPathFreeParserContext:
3913 * @ctxt: the context to free
3914 *
3915 * Free up an xmlXPathParserContext
3916 */
3917void
3918xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3919 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003920 xmlFree(ctxt->valueTab);
3921 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003922 if (ctxt->comp)
3923 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003924 xmlFree(ctxt);
3925}
3926
3927/************************************************************************
3928 * *
3929 * The implicit core function library *
3930 * *
3931 ************************************************************************/
3932
Owen Taylor3473f882001-02-23 17:55:21 +00003933/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003934 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00003935 * @node: a node pointer
3936 *
3937 * Function computing the beginning of the string value of the node,
3938 * used to speed up comparisons
3939 *
3940 * Returns an int usable as a hash
3941 */
3942static unsigned int
3943xmlXPathNodeValHash(xmlNodePtr node) {
3944 int len = 2;
3945 const xmlChar * string = NULL;
3946 xmlNodePtr tmp = NULL;
3947 unsigned int ret = 0;
3948
3949 if (node == NULL)
3950 return(0);
3951
Daniel Veillard9adc0462003-03-24 18:39:54 +00003952 if (node->type == XML_DOCUMENT_NODE) {
3953 tmp = xmlDocGetRootElement((xmlDocPtr) node);
3954 if (tmp == NULL)
3955 node = node->children;
3956 else
3957 node = tmp;
3958
3959 if (node == NULL)
3960 return(0);
3961 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003962
3963 switch (node->type) {
3964 case XML_COMMENT_NODE:
3965 case XML_PI_NODE:
3966 case XML_CDATA_SECTION_NODE:
3967 case XML_TEXT_NODE:
3968 string = node->content;
3969 if (string == NULL)
3970 return(0);
3971 if (string[0] == 0)
3972 return(0);
3973 return(((unsigned int) string[0]) +
3974 (((unsigned int) string[1]) << 8));
3975 case XML_NAMESPACE_DECL:
3976 string = ((xmlNsPtr)node)->href;
3977 if (string == NULL)
3978 return(0);
3979 if (string[0] == 0)
3980 return(0);
3981 return(((unsigned int) string[0]) +
3982 (((unsigned int) string[1]) << 8));
3983 case XML_ATTRIBUTE_NODE:
3984 tmp = ((xmlAttrPtr) node)->children;
3985 break;
3986 case XML_ELEMENT_NODE:
3987 tmp = node->children;
3988 break;
3989 default:
3990 return(0);
3991 }
3992 while (tmp != NULL) {
3993 switch (tmp->type) {
3994 case XML_COMMENT_NODE:
3995 case XML_PI_NODE:
3996 case XML_CDATA_SECTION_NODE:
3997 case XML_TEXT_NODE:
3998 string = tmp->content;
3999 break;
4000 case XML_NAMESPACE_DECL:
4001 string = ((xmlNsPtr)tmp)->href;
4002 break;
4003 default:
4004 break;
4005 }
4006 if ((string != NULL) && (string[0] != 0)) {
4007 if (string[0] == 0)
4008 return(0);
4009 if (len == 1) {
4010 return(ret + (((unsigned int) string[0]) << 8));
4011 }
4012 if (string[1] == 0) {
4013 len = 1;
4014 ret = (unsigned int) string[0];
4015 } else {
4016 return(((unsigned int) string[0]) +
4017 (((unsigned int) string[1]) << 8));
4018 }
4019 }
4020 /*
4021 * Skip to next node
4022 */
4023 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4024 if (tmp->children->type != XML_ENTITY_DECL) {
4025 tmp = tmp->children;
4026 continue;
4027 }
4028 }
4029 if (tmp == node)
4030 break;
4031
4032 if (tmp->next != NULL) {
4033 tmp = tmp->next;
4034 continue;
4035 }
4036
4037 do {
4038 tmp = tmp->parent;
4039 if (tmp == NULL)
4040 break;
4041 if (tmp == node) {
4042 tmp = NULL;
4043 break;
4044 }
4045 if (tmp->next != NULL) {
4046 tmp = tmp->next;
4047 break;
4048 }
4049 } while (tmp != NULL);
4050 }
4051 return(ret);
4052}
4053
4054/**
4055 * xmlXPathStringHash:
4056 * @string: a string
4057 *
4058 * Function computing the beginning of the string value of the node,
4059 * used to speed up comparisons
4060 *
4061 * Returns an int usable as a hash
4062 */
4063static unsigned int
4064xmlXPathStringHash(const xmlChar * string) {
4065 if (string == NULL)
4066 return((unsigned int) 0);
4067 if (string[0] == 0)
4068 return(0);
4069 return(((unsigned int) string[0]) +
4070 (((unsigned int) string[1]) << 8));
4071}
4072
4073/**
Owen Taylor3473f882001-02-23 17:55:21 +00004074 * xmlXPathCompareNodeSetFloat:
4075 * @ctxt: the XPath Parser context
4076 * @inf: less than (1) or greater than (0)
4077 * @strict: is the comparison strict
4078 * @arg: the node set
4079 * @f: the value
4080 *
4081 * Implement the compare operation between a nodeset and a number
4082 * @ns < @val (1, 1, ...
4083 * @ns <= @val (1, 0, ...
4084 * @ns > @val (0, 1, ...
4085 * @ns >= @val (0, 0, ...
4086 *
4087 * If one object to be compared is a node-set and the other is a number,
4088 * then the comparison will be true if and only if there is a node in the
4089 * node-set such that the result of performing the comparison on the number
4090 * to be compared and on the result of converting the string-value of that
4091 * node to a number using the number function is true.
4092 *
4093 * Returns 0 or 1 depending on the results of the test.
4094 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004095static int
Owen Taylor3473f882001-02-23 17:55:21 +00004096xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4097 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4098 int i, ret = 0;
4099 xmlNodeSetPtr ns;
4100 xmlChar *str2;
4101
4102 if ((f == NULL) || (arg == NULL) ||
4103 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4104 xmlXPathFreeObject(arg);
4105 xmlXPathFreeObject(f);
4106 return(0);
4107 }
4108 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004109 if (ns != NULL) {
4110 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004111 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004112 if (str2 != NULL) {
4113 valuePush(ctxt,
4114 xmlXPathNewString(str2));
4115 xmlFree(str2);
4116 xmlXPathNumberFunction(ctxt, 1);
4117 valuePush(ctxt, xmlXPathObjectCopy(f));
4118 ret = xmlXPathCompareValues(ctxt, inf, strict);
4119 if (ret)
4120 break;
4121 }
4122 }
Owen Taylor3473f882001-02-23 17:55:21 +00004123 }
4124 xmlXPathFreeObject(arg);
4125 xmlXPathFreeObject(f);
4126 return(ret);
4127}
4128
4129/**
4130 * xmlXPathCompareNodeSetString:
4131 * @ctxt: the XPath Parser context
4132 * @inf: less than (1) or greater than (0)
4133 * @strict: is the comparison strict
4134 * @arg: the node set
4135 * @s: the value
4136 *
4137 * Implement the compare operation between a nodeset and a string
4138 * @ns < @val (1, 1, ...
4139 * @ns <= @val (1, 0, ...
4140 * @ns > @val (0, 1, ...
4141 * @ns >= @val (0, 0, ...
4142 *
4143 * If one object to be compared is a node-set and the other is a string,
4144 * then the comparison will be true if and only if there is a node in
4145 * the node-set such that the result of performing the comparison on the
4146 * string-value of the node and the other string is true.
4147 *
4148 * Returns 0 or 1 depending on the results of the test.
4149 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004150static int
Owen Taylor3473f882001-02-23 17:55:21 +00004151xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4152 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4153 int i, ret = 0;
4154 xmlNodeSetPtr ns;
4155 xmlChar *str2;
4156
4157 if ((s == NULL) || (arg == NULL) ||
4158 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4159 xmlXPathFreeObject(arg);
4160 xmlXPathFreeObject(s);
4161 return(0);
4162 }
4163 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004164 if (ns != NULL) {
4165 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004166 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004167 if (str2 != NULL) {
4168 valuePush(ctxt,
4169 xmlXPathNewString(str2));
4170 xmlFree(str2);
4171 valuePush(ctxt, xmlXPathObjectCopy(s));
4172 ret = xmlXPathCompareValues(ctxt, inf, strict);
4173 if (ret)
4174 break;
4175 }
4176 }
Owen Taylor3473f882001-02-23 17:55:21 +00004177 }
4178 xmlXPathFreeObject(arg);
4179 xmlXPathFreeObject(s);
4180 return(ret);
4181}
4182
4183/**
4184 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004185 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004186 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004187 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004188 * @arg2: the second node set object
4189 *
4190 * Implement the compare operation on nodesets:
4191 *
4192 * If both objects to be compared are node-sets, then the comparison
4193 * will be true if and only if there is a node in the first node-set
4194 * and a node in the second node-set such that the result of performing
4195 * the comparison on the string-values of the two nodes is true.
4196 * ....
4197 * When neither object to be compared is a node-set and the operator
4198 * is <=, <, >= or >, then the objects are compared by converting both
4199 * objects to numbers and comparing the numbers according to IEEE 754.
4200 * ....
4201 * The number function converts its argument to a number as follows:
4202 * - a string that consists of optional whitespace followed by an
4203 * optional minus sign followed by a Number followed by whitespace
4204 * is converted to the IEEE 754 number that is nearest (according
4205 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4206 * represented by the string; any other string is converted to NaN
4207 *
4208 * Conclusion all nodes need to be converted first to their string value
4209 * and then the comparison must be done when possible
4210 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004211static int
4212xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004213 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4214 int i, j, init = 0;
4215 double val1;
4216 double *values2;
4217 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004218 xmlNodeSetPtr ns1;
4219 xmlNodeSetPtr ns2;
4220
4221 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004222 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4223 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004224 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004225 }
Owen Taylor3473f882001-02-23 17:55:21 +00004226 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004227 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4228 xmlXPathFreeObject(arg1);
4229 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004230 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004231 }
Owen Taylor3473f882001-02-23 17:55:21 +00004232
4233 ns1 = arg1->nodesetval;
4234 ns2 = arg2->nodesetval;
4235
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004236 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004237 xmlXPathFreeObject(arg1);
4238 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004239 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004240 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004241 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004242 xmlXPathFreeObject(arg1);
4243 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004244 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004245 }
Owen Taylor3473f882001-02-23 17:55:21 +00004246
4247 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4248 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004249 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004250 xmlXPathFreeObject(arg1);
4251 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004252 return(0);
4253 }
4254 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004255 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004256 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004257 continue;
4258 for (j = 0;j < ns2->nodeNr;j++) {
4259 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004260 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004261 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004262 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004263 continue;
4264 if (inf && strict)
4265 ret = (val1 < values2[j]);
4266 else if (inf && !strict)
4267 ret = (val1 <= values2[j]);
4268 else if (!inf && strict)
4269 ret = (val1 > values2[j]);
4270 else if (!inf && !strict)
4271 ret = (val1 >= values2[j]);
4272 if (ret)
4273 break;
4274 }
4275 if (ret)
4276 break;
4277 init = 1;
4278 }
4279 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004280 xmlXPathFreeObject(arg1);
4281 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004282 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004283}
4284
4285/**
4286 * xmlXPathCompareNodeSetValue:
4287 * @ctxt: the XPath Parser context
4288 * @inf: less than (1) or greater than (0)
4289 * @strict: is the comparison strict
4290 * @arg: the node set
4291 * @val: the value
4292 *
4293 * Implement the compare operation between a nodeset and a value
4294 * @ns < @val (1, 1, ...
4295 * @ns <= @val (1, 0, ...
4296 * @ns > @val (0, 1, ...
4297 * @ns >= @val (0, 0, ...
4298 *
4299 * If one object to be compared is a node-set and the other is a boolean,
4300 * then the comparison will be true if and only if the result of performing
4301 * the comparison on the boolean and on the result of converting
4302 * the node-set to a boolean using the boolean function is true.
4303 *
4304 * Returns 0 or 1 depending on the results of the test.
4305 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004306static int
Owen Taylor3473f882001-02-23 17:55:21 +00004307xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4308 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4309 if ((val == NULL) || (arg == NULL) ||
4310 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4311 return(0);
4312
4313 switch(val->type) {
4314 case XPATH_NUMBER:
4315 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4316 case XPATH_NODESET:
4317 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004318 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004319 case XPATH_STRING:
4320 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4321 case XPATH_BOOLEAN:
4322 valuePush(ctxt, arg);
4323 xmlXPathBooleanFunction(ctxt, 1);
4324 valuePush(ctxt, val);
4325 return(xmlXPathCompareValues(ctxt, inf, strict));
4326 default:
4327 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004328 }
4329 return(0);
4330}
4331
4332/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004333 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004334 * @arg: the nodeset object argument
4335 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004336 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004337 *
4338 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4339 * If one object to be compared is a node-set and the other is a string,
4340 * then the comparison will be true if and only if there is a node in
4341 * the node-set such that the result of performing the comparison on the
4342 * string-value of the node and the other string is true.
4343 *
4344 * Returns 0 or 1 depending on the results of the test.
4345 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004346static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004347xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004348{
Owen Taylor3473f882001-02-23 17:55:21 +00004349 int i;
4350 xmlNodeSetPtr ns;
4351 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004352 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004353
4354 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004355 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4356 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004357 ns = arg->nodesetval;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004358 hash = xmlXPathStringHash(str);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004359 if (ns == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004360 return (0);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004361 if (ns->nodeNr <= 0) {
4362 if (hash == 0)
William M. Brack0c022ad2002-07-12 00:56:01 +00004363 return(neq ^ 1);
4364 return(neq);
Daniel Veillard73c9c042001-07-05 20:02:54 +00004365 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004366 for (i = 0; i < ns->nodeNr; i++) {
4367 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4368 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4369 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4370 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004371 if (neq)
4372 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004373 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004374 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4375 if (neq)
4376 continue;
4377 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004378 } else if (neq) {
4379 if (str2 != NULL)
4380 xmlFree(str2);
4381 return (1);
4382 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004383 if (str2 != NULL)
4384 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004385 } else if (neq)
4386 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004387 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004388 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004389}
4390
4391/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004392 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004393 * @arg: the nodeset object argument
4394 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004395 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004396 *
4397 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4398 * If one object to be compared is a node-set and the other is a number,
4399 * then the comparison will be true if and only if there is a node in
4400 * the node-set such that the result of performing the comparison on the
4401 * number to be compared and on the result of converting the string-value
4402 * of that node to a number using the number function is true.
4403 *
4404 * Returns 0 or 1 depending on the results of the test.
4405 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004406static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004407xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4408 xmlXPathObjectPtr arg, double f, int neq) {
4409 int i, ret=0;
4410 xmlNodeSetPtr ns;
4411 xmlChar *str2;
4412 xmlXPathObjectPtr val;
4413 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004414
4415 if ((arg == NULL) ||
4416 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4417 return(0);
4418
William M. Brack0c022ad2002-07-12 00:56:01 +00004419 ns = arg->nodesetval;
4420 if (ns != NULL) {
4421 for (i=0;i<ns->nodeNr;i++) {
4422 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4423 if (str2 != NULL) {
4424 valuePush(ctxt, xmlXPathNewString(str2));
4425 xmlFree(str2);
4426 xmlXPathNumberFunction(ctxt, 1);
4427 val = valuePop(ctxt);
4428 v = val->floatval;
4429 xmlXPathFreeObject(val);
4430 if (!xmlXPathIsNaN(v)) {
4431 if ((!neq) && (v==f)) {
4432 ret = 1;
4433 break;
4434 } else if ((neq) && (v!=f)) {
4435 ret = 1;
4436 break;
4437 }
4438 }
4439 }
4440 }
4441 }
4442
4443 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004444}
4445
4446
4447/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004448 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004449 * @arg1: first nodeset object argument
4450 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004451 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004452 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004453 * Implement the equal / not equal operation on XPath nodesets:
4454 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004455 * If both objects to be compared are node-sets, then the comparison
4456 * will be true if and only if there is a node in the first node-set and
4457 * a node in the second node-set such that the result of performing the
4458 * comparison on the string-values of the two nodes is true.
4459 *
4460 * (needless to say, this is a costly operation)
4461 *
4462 * Returns 0 or 1 depending on the results of the test.
4463 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004464static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004465xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004466 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004467 unsigned int *hashs1;
4468 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004469 xmlChar **values1;
4470 xmlChar **values2;
4471 int ret = 0;
4472 xmlNodeSetPtr ns1;
4473 xmlNodeSetPtr ns2;
4474
4475 if ((arg1 == NULL) ||
4476 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4477 return(0);
4478 if ((arg2 == NULL) ||
4479 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4480 return(0);
4481
4482 ns1 = arg1->nodesetval;
4483 ns2 = arg2->nodesetval;
4484
Daniel Veillard911f49a2001-04-07 15:39:35 +00004485 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004486 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004487 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004488 return(0);
4489
4490 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004491 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004492 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004493 if (neq == 0)
4494 for (i = 0;i < ns1->nodeNr;i++)
4495 for (j = 0;j < ns2->nodeNr;j++)
4496 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4497 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004498
4499 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004500 if (values1 == NULL) {
4501 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004502 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004503 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004504 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4505 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004506 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004507 xmlFree(values1);
4508 return(0);
4509 }
Owen Taylor3473f882001-02-23 17:55:21 +00004510 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4511 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4512 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004513 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004514 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004515 xmlFree(values1);
4516 return(0);
4517 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004518 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4519 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004520 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004521 xmlFree(hashs1);
4522 xmlFree(values1);
4523 xmlFree(values2);
4524 return(0);
4525 }
Owen Taylor3473f882001-02-23 17:55:21 +00004526 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4527 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004528 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004529 for (j = 0;j < ns2->nodeNr;j++) {
4530 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004531 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004532 if (hashs1[i] != hashs2[j]) {
4533 if (neq) {
4534 ret = 1;
4535 break;
4536 }
4537 }
4538 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004539 if (values1[i] == NULL)
4540 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4541 if (values2[j] == NULL)
4542 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004543 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004544 if (ret)
4545 break;
4546 }
Owen Taylor3473f882001-02-23 17:55:21 +00004547 }
4548 if (ret)
4549 break;
4550 }
4551 for (i = 0;i < ns1->nodeNr;i++)
4552 if (values1[i] != NULL)
4553 xmlFree(values1[i]);
4554 for (j = 0;j < ns2->nodeNr;j++)
4555 if (values2[j] != NULL)
4556 xmlFree(values2[j]);
4557 xmlFree(values1);
4558 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004559 xmlFree(hashs1);
4560 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004561 return(ret);
4562}
4563
William M. Brack0c022ad2002-07-12 00:56:01 +00004564static int
4565xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4566 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004567 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004568 /*
4569 *At this point we are assured neither arg1 nor arg2
4570 *is a nodeset, so we can just pick the appropriate routine.
4571 */
Owen Taylor3473f882001-02-23 17:55:21 +00004572 switch (arg1->type) {
4573 case XPATH_UNDEFINED:
4574#ifdef DEBUG_EXPR
4575 xmlGenericError(xmlGenericErrorContext,
4576 "Equal: undefined\n");
4577#endif
4578 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004579 case XPATH_BOOLEAN:
4580 switch (arg2->type) {
4581 case XPATH_UNDEFINED:
4582#ifdef DEBUG_EXPR
4583 xmlGenericError(xmlGenericErrorContext,
4584 "Equal: undefined\n");
4585#endif
4586 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004587 case XPATH_BOOLEAN:
4588#ifdef DEBUG_EXPR
4589 xmlGenericError(xmlGenericErrorContext,
4590 "Equal: %d boolean %d \n",
4591 arg1->boolval, arg2->boolval);
4592#endif
4593 ret = (arg1->boolval == arg2->boolval);
4594 break;
4595 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004596 ret = (arg1->boolval ==
4597 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004598 break;
4599 case XPATH_STRING:
4600 if ((arg2->stringval == NULL) ||
4601 (arg2->stringval[0] == 0)) ret = 0;
4602 else
4603 ret = 1;
4604 ret = (arg1->boolval == ret);
4605 break;
4606 case XPATH_USERS:
4607 case XPATH_POINT:
4608 case XPATH_RANGE:
4609 case XPATH_LOCATIONSET:
4610 TODO
4611 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004612 case XPATH_NODESET:
4613 case XPATH_XSLT_TREE:
4614 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004615 }
4616 break;
4617 case XPATH_NUMBER:
4618 switch (arg2->type) {
4619 case XPATH_UNDEFINED:
4620#ifdef DEBUG_EXPR
4621 xmlGenericError(xmlGenericErrorContext,
4622 "Equal: undefined\n");
4623#endif
4624 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004625 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004626 ret = (arg2->boolval==
4627 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004628 break;
4629 case XPATH_STRING:
4630 valuePush(ctxt, arg2);
4631 xmlXPathNumberFunction(ctxt, 1);
4632 arg2 = valuePop(ctxt);
4633 /* no break on purpose */
4634 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004635 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004636 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4637 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004638 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4639 if (xmlXPathIsInf(arg2->floatval) == 1)
4640 ret = 1;
4641 else
4642 ret = 0;
4643 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4644 if (xmlXPathIsInf(arg2->floatval) == -1)
4645 ret = 1;
4646 else
4647 ret = 0;
4648 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4649 if (xmlXPathIsInf(arg1->floatval) == 1)
4650 ret = 1;
4651 else
4652 ret = 0;
4653 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4654 if (xmlXPathIsInf(arg1->floatval) == -1)
4655 ret = 1;
4656 else
4657 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004658 } else {
4659 ret = (arg1->floatval == arg2->floatval);
4660 }
Owen Taylor3473f882001-02-23 17:55:21 +00004661 break;
4662 case XPATH_USERS:
4663 case XPATH_POINT:
4664 case XPATH_RANGE:
4665 case XPATH_LOCATIONSET:
4666 TODO
4667 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004668 case XPATH_NODESET:
4669 case XPATH_XSLT_TREE:
4670 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004671 }
4672 break;
4673 case XPATH_STRING:
4674 switch (arg2->type) {
4675 case XPATH_UNDEFINED:
4676#ifdef DEBUG_EXPR
4677 xmlGenericError(xmlGenericErrorContext,
4678 "Equal: undefined\n");
4679#endif
4680 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004681 case XPATH_BOOLEAN:
4682 if ((arg1->stringval == NULL) ||
4683 (arg1->stringval[0] == 0)) ret = 0;
4684 else
4685 ret = 1;
4686 ret = (arg2->boolval == ret);
4687 break;
4688 case XPATH_STRING:
4689 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4690 break;
4691 case XPATH_NUMBER:
4692 valuePush(ctxt, arg1);
4693 xmlXPathNumberFunction(ctxt, 1);
4694 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004695 /* Hand check NaN and Infinity equalities */
Daniel Veillard21458c82002-03-27 16:12:22 +00004696 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4697 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004698 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4699 if (xmlXPathIsInf(arg2->floatval) == 1)
4700 ret = 1;
4701 else
4702 ret = 0;
4703 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4704 if (xmlXPathIsInf(arg2->floatval) == -1)
4705 ret = 1;
4706 else
4707 ret = 0;
4708 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4709 if (xmlXPathIsInf(arg1->floatval) == 1)
4710 ret = 1;
4711 else
4712 ret = 0;
4713 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4714 if (xmlXPathIsInf(arg1->floatval) == -1)
4715 ret = 1;
4716 else
4717 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004718 } else {
4719 ret = (arg1->floatval == arg2->floatval);
4720 }
Owen Taylor3473f882001-02-23 17:55:21 +00004721 break;
4722 case XPATH_USERS:
4723 case XPATH_POINT:
4724 case XPATH_RANGE:
4725 case XPATH_LOCATIONSET:
4726 TODO
4727 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004728 case XPATH_NODESET:
4729 case XPATH_XSLT_TREE:
4730 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004731 }
4732 break;
4733 case XPATH_USERS:
4734 case XPATH_POINT:
4735 case XPATH_RANGE:
4736 case XPATH_LOCATIONSET:
4737 TODO
4738 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004739 case XPATH_NODESET:
4740 case XPATH_XSLT_TREE:
4741 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004742 }
4743 xmlXPathFreeObject(arg1);
4744 xmlXPathFreeObject(arg2);
4745 return(ret);
4746}
4747
William M. Brack0c022ad2002-07-12 00:56:01 +00004748/**
4749 * xmlXPathEqualValues:
4750 * @ctxt: the XPath Parser context
4751 *
4752 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4753 *
4754 * Returns 0 or 1 depending on the results of the test.
4755 */
4756int
4757xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4758 xmlXPathObjectPtr arg1, arg2, argtmp;
4759 int ret = 0;
4760
4761 arg2 = valuePop(ctxt);
4762 arg1 = valuePop(ctxt);
4763 if ((arg1 == NULL) || (arg2 == NULL)) {
4764 if (arg1 != NULL)
4765 xmlXPathFreeObject(arg1);
4766 else
4767 xmlXPathFreeObject(arg2);
4768 XP_ERROR0(XPATH_INVALID_OPERAND);
4769 }
4770
4771 if (arg1 == arg2) {
4772#ifdef DEBUG_EXPR
4773 xmlGenericError(xmlGenericErrorContext,
4774 "Equal: by pointer\n");
4775#endif
4776 return(1);
4777 }
4778
4779 /*
4780 *If either argument is a nodeset, it's a 'special case'
4781 */
4782 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4783 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4784 /*
4785 *Hack it to assure arg1 is the nodeset
4786 */
4787 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4788 argtmp = arg2;
4789 arg2 = arg1;
4790 arg1 = argtmp;
4791 }
4792 switch (arg2->type) {
4793 case XPATH_UNDEFINED:
4794#ifdef DEBUG_EXPR
4795 xmlGenericError(xmlGenericErrorContext,
4796 "Equal: undefined\n");
4797#endif
4798 break;
4799 case XPATH_NODESET:
4800 case XPATH_XSLT_TREE:
4801 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4802 break;
4803 case XPATH_BOOLEAN:
4804 if ((arg1->nodesetval == NULL) ||
4805 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4806 else
4807 ret = 1;
4808 ret = (ret == arg2->boolval);
4809 break;
4810 case XPATH_NUMBER:
4811 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4812 break;
4813 case XPATH_STRING:
4814 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4815 break;
4816 case XPATH_USERS:
4817 case XPATH_POINT:
4818 case XPATH_RANGE:
4819 case XPATH_LOCATIONSET:
4820 TODO
4821 break;
4822 }
4823 xmlXPathFreeObject(arg1);
4824 xmlXPathFreeObject(arg2);
4825 return(ret);
4826 }
4827
4828 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4829}
4830
4831/**
4832 * xmlXPathNotEqualValues:
4833 * @ctxt: the XPath Parser context
4834 *
4835 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4836 *
4837 * Returns 0 or 1 depending on the results of the test.
4838 */
4839int
4840xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4841 xmlXPathObjectPtr arg1, arg2, argtmp;
4842 int ret = 0;
4843
4844 arg2 = valuePop(ctxt);
4845 arg1 = valuePop(ctxt);
4846 if ((arg1 == NULL) || (arg2 == NULL)) {
4847 if (arg1 != NULL)
4848 xmlXPathFreeObject(arg1);
4849 else
4850 xmlXPathFreeObject(arg2);
4851 XP_ERROR0(XPATH_INVALID_OPERAND);
4852 }
4853
4854 if (arg1 == arg2) {
4855#ifdef DEBUG_EXPR
4856 xmlGenericError(xmlGenericErrorContext,
4857 "NotEqual: by pointer\n");
4858#endif
4859 return(0);
4860 }
4861
4862 /*
4863 *If either argument is a nodeset, it's a 'special case'
4864 */
4865 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4866 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4867 /*
4868 *Hack it to assure arg1 is the nodeset
4869 */
4870 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4871 argtmp = arg2;
4872 arg2 = arg1;
4873 arg1 = argtmp;
4874 }
4875 switch (arg2->type) {
4876 case XPATH_UNDEFINED:
4877#ifdef DEBUG_EXPR
4878 xmlGenericError(xmlGenericErrorContext,
4879 "NotEqual: undefined\n");
4880#endif
4881 break;
4882 case XPATH_NODESET:
4883 case XPATH_XSLT_TREE:
4884 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4885 break;
4886 case XPATH_BOOLEAN:
4887 if ((arg1->nodesetval == NULL) ||
4888 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4889 else
4890 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004891 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004892 break;
4893 case XPATH_NUMBER:
4894 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4895 break;
4896 case XPATH_STRING:
4897 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4898 break;
4899 case XPATH_USERS:
4900 case XPATH_POINT:
4901 case XPATH_RANGE:
4902 case XPATH_LOCATIONSET:
4903 TODO
4904 break;
4905 }
4906 xmlXPathFreeObject(arg1);
4907 xmlXPathFreeObject(arg2);
4908 return(ret);
4909 }
4910
4911 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4912}
Owen Taylor3473f882001-02-23 17:55:21 +00004913
4914/**
4915 * xmlXPathCompareValues:
4916 * @ctxt: the XPath Parser context
4917 * @inf: less than (1) or greater than (0)
4918 * @strict: is the comparison strict
4919 *
4920 * Implement the compare operation on XPath objects:
4921 * @arg1 < @arg2 (1, 1, ...
4922 * @arg1 <= @arg2 (1, 0, ...
4923 * @arg1 > @arg2 (0, 1, ...
4924 * @arg1 >= @arg2 (0, 0, ...
4925 *
4926 * When neither object to be compared is a node-set and the operator is
4927 * <=, <, >=, >, then the objects are compared by converted both objects
4928 * to numbers and comparing the numbers according to IEEE 754. The <
4929 * comparison will be true if and only if the first number is less than the
4930 * second number. The <= comparison will be true if and only if the first
4931 * number is less than or equal to the second number. The > comparison
4932 * will be true if and only if the first number is greater than the second
4933 * number. The >= comparison will be true if and only if the first number
4934 * is greater than or equal to the second number.
4935 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004936 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004937 */
4938int
4939xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004940 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004941 xmlXPathObjectPtr arg1, arg2;
4942
William M. Brack0c022ad2002-07-12 00:56:01 +00004943 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004944 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004945 if ((arg1 == NULL) || (arg2 == NULL)) {
4946 if (arg1 != NULL)
4947 xmlXPathFreeObject(arg1);
4948 else
4949 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004950 XP_ERROR0(XPATH_INVALID_OPERAND);
4951 }
4952
William M. Brack0c022ad2002-07-12 00:56:01 +00004953 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4954 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4955 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4956 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004957 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004958 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004959 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004960 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4961 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004962 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004963 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4964 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00004965 }
4966 }
4967 return(ret);
4968 }
4969
4970 if (arg1->type != XPATH_NUMBER) {
4971 valuePush(ctxt, arg1);
4972 xmlXPathNumberFunction(ctxt, 1);
4973 arg1 = valuePop(ctxt);
4974 }
4975 if (arg1->type != XPATH_NUMBER) {
4976 xmlXPathFreeObject(arg1);
4977 xmlXPathFreeObject(arg2);
4978 XP_ERROR0(XPATH_INVALID_OPERAND);
4979 }
4980 if (arg2->type != XPATH_NUMBER) {
4981 valuePush(ctxt, arg2);
4982 xmlXPathNumberFunction(ctxt, 1);
4983 arg2 = valuePop(ctxt);
4984 }
4985 if (arg2->type != XPATH_NUMBER) {
4986 xmlXPathFreeObject(arg1);
4987 xmlXPathFreeObject(arg2);
4988 XP_ERROR0(XPATH_INVALID_OPERAND);
4989 }
4990 /*
4991 * Add tests for infinity and nan
4992 * => feedback on 3.4 for Inf and NaN
4993 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004994 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00004995 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004996 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004997 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004998 arg1i=xmlXPathIsInf(arg1->floatval);
4999 arg2i=xmlXPathIsInf(arg2->floatval);
5000 if (inf && strict) {
5001 if ((arg1i == -1 && arg2i != -1) ||
5002 (arg2i == 1 && arg1i != 1)) {
5003 ret = 1;
5004 } else if (arg1i == 0 && arg2i == 0) {
5005 ret = (arg1->floatval < arg2->floatval);
5006 } else {
5007 ret = 0;
5008 }
5009 }
5010 else if (inf && !strict) {
5011 if (arg1i == -1 || arg2i == 1) {
5012 ret = 1;
5013 } else if (arg1i == 0 && arg2i == 0) {
5014 ret = (arg1->floatval <= arg2->floatval);
5015 } else {
5016 ret = 0;
5017 }
5018 }
5019 else if (!inf && strict) {
5020 if ((arg1i == 1 && arg2i != 1) ||
5021 (arg2i == -1 && arg1i != -1)) {
5022 ret = 1;
5023 } else if (arg1i == 0 && arg2i == 0) {
5024 ret = (arg1->floatval > arg2->floatval);
5025 } else {
5026 ret = 0;
5027 }
5028 }
5029 else if (!inf && !strict) {
5030 if (arg1i == 1 || arg2i == -1) {
5031 ret = 1;
5032 } else if (arg1i == 0 && arg2i == 0) {
5033 ret = (arg1->floatval >= arg2->floatval);
5034 } else {
5035 ret = 0;
5036 }
5037 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005038 }
Owen Taylor3473f882001-02-23 17:55:21 +00005039 xmlXPathFreeObject(arg1);
5040 xmlXPathFreeObject(arg2);
5041 return(ret);
5042}
5043
5044/**
5045 * xmlXPathValueFlipSign:
5046 * @ctxt: the XPath Parser context
5047 *
5048 * Implement the unary - operation on an XPath object
5049 * The numeric operators convert their operands to numbers as if
5050 * by calling the number function.
5051 */
5052void
5053xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005054 CAST_TO_NUMBER;
5055 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005056 if (xmlXPathIsNaN(ctxt->value->floatval))
5057 ctxt->value->floatval=xmlXPathNAN;
5058 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5059 ctxt->value->floatval=xmlXPathNINF;
5060 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5061 ctxt->value->floatval=xmlXPathPINF;
5062 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005063 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5064 ctxt->value->floatval = xmlXPathNZERO;
5065 else
5066 ctxt->value->floatval = 0;
5067 }
5068 else
5069 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005070}
5071
5072/**
5073 * xmlXPathAddValues:
5074 * @ctxt: the XPath Parser context
5075 *
5076 * Implement the add operation on XPath objects:
5077 * The numeric operators convert their operands to numbers as if
5078 * by calling the number function.
5079 */
5080void
5081xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5082 xmlXPathObjectPtr arg;
5083 double val;
5084
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005085 arg = valuePop(ctxt);
5086 if (arg == NULL)
5087 XP_ERROR(XPATH_INVALID_OPERAND);
5088 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005089 xmlXPathFreeObject(arg);
5090
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005091 CAST_TO_NUMBER;
5092 CHECK_TYPE(XPATH_NUMBER);
5093 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005094}
5095
5096/**
5097 * xmlXPathSubValues:
5098 * @ctxt: the XPath Parser context
5099 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005100 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005101 * The numeric operators convert their operands to numbers as if
5102 * by calling the number function.
5103 */
5104void
5105xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5106 xmlXPathObjectPtr arg;
5107 double val;
5108
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005109 arg = valuePop(ctxt);
5110 if (arg == NULL)
5111 XP_ERROR(XPATH_INVALID_OPERAND);
5112 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005113 xmlXPathFreeObject(arg);
5114
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005115 CAST_TO_NUMBER;
5116 CHECK_TYPE(XPATH_NUMBER);
5117 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005118}
5119
5120/**
5121 * xmlXPathMultValues:
5122 * @ctxt: the XPath Parser context
5123 *
5124 * Implement the multiply operation on XPath objects:
5125 * The numeric operators convert their operands to numbers as if
5126 * by calling the number function.
5127 */
5128void
5129xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5130 xmlXPathObjectPtr arg;
5131 double val;
5132
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005133 arg = valuePop(ctxt);
5134 if (arg == NULL)
5135 XP_ERROR(XPATH_INVALID_OPERAND);
5136 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005137 xmlXPathFreeObject(arg);
5138
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005139 CAST_TO_NUMBER;
5140 CHECK_TYPE(XPATH_NUMBER);
5141 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005142}
5143
5144/**
5145 * xmlXPathDivValues:
5146 * @ctxt: the XPath Parser context
5147 *
5148 * Implement the div operation on XPath objects @arg1 / @arg2:
5149 * The numeric operators convert their operands to numbers as if
5150 * by calling the number function.
5151 */
5152void
5153xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5154 xmlXPathObjectPtr arg;
5155 double val;
5156
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005157 arg = valuePop(ctxt);
5158 if (arg == NULL)
5159 XP_ERROR(XPATH_INVALID_OPERAND);
5160 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005161 xmlXPathFreeObject(arg);
5162
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005163 CAST_TO_NUMBER;
5164 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005165 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5166 ctxt->value->floatval = xmlXPathNAN;
5167 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005168 if (ctxt->value->floatval == 0)
5169 ctxt->value->floatval = xmlXPathNAN;
5170 else if (ctxt->value->floatval > 0)
5171 ctxt->value->floatval = xmlXPathNINF;
5172 else if (ctxt->value->floatval < 0)
5173 ctxt->value->floatval = xmlXPathPINF;
5174 }
5175 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005176 if (ctxt->value->floatval == 0)
5177 ctxt->value->floatval = xmlXPathNAN;
5178 else if (ctxt->value->floatval > 0)
5179 ctxt->value->floatval = xmlXPathPINF;
5180 else if (ctxt->value->floatval < 0)
5181 ctxt->value->floatval = xmlXPathNINF;
5182 } else
5183 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005184}
5185
5186/**
5187 * xmlXPathModValues:
5188 * @ctxt: the XPath Parser context
5189 *
5190 * Implement the mod operation on XPath objects: @arg1 / @arg2
5191 * The numeric operators convert their operands to numbers as if
5192 * by calling the number function.
5193 */
5194void
5195xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5196 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005197 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005198
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005199 arg = valuePop(ctxt);
5200 if (arg == NULL)
5201 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005202 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005203 xmlXPathFreeObject(arg);
5204
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005205 CAST_TO_NUMBER;
5206 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005207 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005208 if (arg2 == 0)
5209 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005210 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005211 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005212 }
Owen Taylor3473f882001-02-23 17:55:21 +00005213}
5214
5215/************************************************************************
5216 * *
5217 * The traversal functions *
5218 * *
5219 ************************************************************************/
5220
Owen Taylor3473f882001-02-23 17:55:21 +00005221/*
5222 * A traversal function enumerates nodes along an axis.
5223 * Initially it must be called with NULL, and it indicates
5224 * termination on the axis by returning NULL.
5225 */
5226typedef xmlNodePtr (*xmlXPathTraversalFunction)
5227 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5228
5229/**
5230 * xmlXPathNextSelf:
5231 * @ctxt: the XPath Parser context
5232 * @cur: the current node in the traversal
5233 *
5234 * Traversal function for the "self" direction
5235 * The self axis contains just the context node itself
5236 *
5237 * Returns the next element following that axis
5238 */
5239xmlNodePtr
5240xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5241 if (cur == NULL)
5242 return(ctxt->context->node);
5243 return(NULL);
5244}
5245
5246/**
5247 * xmlXPathNextChild:
5248 * @ctxt: the XPath Parser context
5249 * @cur: the current node in the traversal
5250 *
5251 * Traversal function for the "child" direction
5252 * The child axis contains the children of the context node in document order.
5253 *
5254 * Returns the next element following that axis
5255 */
5256xmlNodePtr
5257xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5258 if (cur == NULL) {
5259 if (ctxt->context->node == NULL) return(NULL);
5260 switch (ctxt->context->node->type) {
5261 case XML_ELEMENT_NODE:
5262 case XML_TEXT_NODE:
5263 case XML_CDATA_SECTION_NODE:
5264 case XML_ENTITY_REF_NODE:
5265 case XML_ENTITY_NODE:
5266 case XML_PI_NODE:
5267 case XML_COMMENT_NODE:
5268 case XML_NOTATION_NODE:
5269 case XML_DTD_NODE:
5270 return(ctxt->context->node->children);
5271 case XML_DOCUMENT_NODE:
5272 case XML_DOCUMENT_TYPE_NODE:
5273 case XML_DOCUMENT_FRAG_NODE:
5274 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005275#ifdef LIBXML_DOCB_ENABLED
5276 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005277#endif
5278 return(((xmlDocPtr) ctxt->context->node)->children);
5279 case XML_ELEMENT_DECL:
5280 case XML_ATTRIBUTE_DECL:
5281 case XML_ENTITY_DECL:
5282 case XML_ATTRIBUTE_NODE:
5283 case XML_NAMESPACE_DECL:
5284 case XML_XINCLUDE_START:
5285 case XML_XINCLUDE_END:
5286 return(NULL);
5287 }
5288 return(NULL);
5289 }
5290 if ((cur->type == XML_DOCUMENT_NODE) ||
5291 (cur->type == XML_HTML_DOCUMENT_NODE))
5292 return(NULL);
5293 return(cur->next);
5294}
5295
5296/**
5297 * xmlXPathNextDescendant:
5298 * @ctxt: the XPath Parser context
5299 * @cur: the current node in the traversal
5300 *
5301 * Traversal function for the "descendant" direction
5302 * the descendant axis contains the descendants of the context node in document
5303 * order; a descendant is a child or a child of a child and so on.
5304 *
5305 * Returns the next element following that axis
5306 */
5307xmlNodePtr
5308xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5309 if (cur == NULL) {
5310 if (ctxt->context->node == NULL)
5311 return(NULL);
5312 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5313 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5314 return(NULL);
5315
5316 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5317 return(ctxt->context->doc->children);
5318 return(ctxt->context->node->children);
5319 }
5320
Daniel Veillard567e1b42001-08-01 15:53:47 +00005321 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005322 /*
5323 * Do not descend on entities declarations
5324 */
5325 if (cur->children->type != XML_ENTITY_DECL) {
5326 cur = cur->children;
5327 /*
5328 * Skip DTDs
5329 */
5330 if (cur->type != XML_DTD_NODE)
5331 return(cur);
5332 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005333 }
5334
5335 if (cur == ctxt->context->node) return(NULL);
5336
Daniel Veillard68e9e742002-11-16 15:35:11 +00005337 while (cur->next != NULL) {
5338 cur = cur->next;
5339 if ((cur->type != XML_ENTITY_DECL) &&
5340 (cur->type != XML_DTD_NODE))
5341 return(cur);
5342 }
Owen Taylor3473f882001-02-23 17:55:21 +00005343
5344 do {
5345 cur = cur->parent;
5346 if (cur == NULL) return(NULL);
5347 if (cur == ctxt->context->node) return(NULL);
5348 if (cur->next != NULL) {
5349 cur = cur->next;
5350 return(cur);
5351 }
5352 } while (cur != NULL);
5353 return(cur);
5354}
5355
5356/**
5357 * xmlXPathNextDescendantOrSelf:
5358 * @ctxt: the XPath Parser context
5359 * @cur: the current node in the traversal
5360 *
5361 * Traversal function for the "descendant-or-self" direction
5362 * the descendant-or-self axis contains the context node and the descendants
5363 * of the context node in document order; thus the context node is the first
5364 * node on the axis, and the first child of the context node is the second node
5365 * on the axis
5366 *
5367 * Returns the next element following that axis
5368 */
5369xmlNodePtr
5370xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5371 if (cur == NULL) {
5372 if (ctxt->context->node == NULL)
5373 return(NULL);
5374 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5375 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5376 return(NULL);
5377 return(ctxt->context->node);
5378 }
5379
5380 return(xmlXPathNextDescendant(ctxt, cur));
5381}
5382
5383/**
5384 * xmlXPathNextParent:
5385 * @ctxt: the XPath Parser context
5386 * @cur: the current node in the traversal
5387 *
5388 * Traversal function for the "parent" direction
5389 * The parent axis contains the parent of the context node, if there is one.
5390 *
5391 * Returns the next element following that axis
5392 */
5393xmlNodePtr
5394xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5395 /*
5396 * the parent of an attribute or namespace node is the element
5397 * to which the attribute or namespace node is attached
5398 * Namespace handling !!!
5399 */
5400 if (cur == NULL) {
5401 if (ctxt->context->node == NULL) return(NULL);
5402 switch (ctxt->context->node->type) {
5403 case XML_ELEMENT_NODE:
5404 case XML_TEXT_NODE:
5405 case XML_CDATA_SECTION_NODE:
5406 case XML_ENTITY_REF_NODE:
5407 case XML_ENTITY_NODE:
5408 case XML_PI_NODE:
5409 case XML_COMMENT_NODE:
5410 case XML_NOTATION_NODE:
5411 case XML_DTD_NODE:
5412 case XML_ELEMENT_DECL:
5413 case XML_ATTRIBUTE_DECL:
5414 case XML_XINCLUDE_START:
5415 case XML_XINCLUDE_END:
5416 case XML_ENTITY_DECL:
5417 if (ctxt->context->node->parent == NULL)
5418 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005419 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005420 ((ctxt->context->node->parent->name[0] == ' ') ||
5421 (xmlStrEqual(ctxt->context->node->parent->name,
5422 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005423 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005424 return(ctxt->context->node->parent);
5425 case XML_ATTRIBUTE_NODE: {
5426 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5427
5428 return(att->parent);
5429 }
5430 case XML_DOCUMENT_NODE:
5431 case XML_DOCUMENT_TYPE_NODE:
5432 case XML_DOCUMENT_FRAG_NODE:
5433 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005434#ifdef LIBXML_DOCB_ENABLED
5435 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005436#endif
5437 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005438 case XML_NAMESPACE_DECL: {
5439 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5440
5441 if ((ns->next != NULL) &&
5442 (ns->next->type != XML_NAMESPACE_DECL))
5443 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005444 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005445 }
Owen Taylor3473f882001-02-23 17:55:21 +00005446 }
5447 }
5448 return(NULL);
5449}
5450
5451/**
5452 * xmlXPathNextAncestor:
5453 * @ctxt: the XPath Parser context
5454 * @cur: the current node in the traversal
5455 *
5456 * Traversal function for the "ancestor" direction
5457 * the ancestor axis contains the ancestors of the context node; the ancestors
5458 * of the context node consist of the parent of context node and the parent's
5459 * parent and so on; the nodes are ordered in reverse document order; thus the
5460 * parent is the first node on the axis, and the parent's parent is the second
5461 * node on the axis
5462 *
5463 * Returns the next element following that axis
5464 */
5465xmlNodePtr
5466xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5467 /*
5468 * the parent of an attribute or namespace node is the element
5469 * to which the attribute or namespace node is attached
5470 * !!!!!!!!!!!!!
5471 */
5472 if (cur == NULL) {
5473 if (ctxt->context->node == NULL) return(NULL);
5474 switch (ctxt->context->node->type) {
5475 case XML_ELEMENT_NODE:
5476 case XML_TEXT_NODE:
5477 case XML_CDATA_SECTION_NODE:
5478 case XML_ENTITY_REF_NODE:
5479 case XML_ENTITY_NODE:
5480 case XML_PI_NODE:
5481 case XML_COMMENT_NODE:
5482 case XML_DTD_NODE:
5483 case XML_ELEMENT_DECL:
5484 case XML_ATTRIBUTE_DECL:
5485 case XML_ENTITY_DECL:
5486 case XML_NOTATION_NODE:
5487 case XML_XINCLUDE_START:
5488 case XML_XINCLUDE_END:
5489 if (ctxt->context->node->parent == NULL)
5490 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005491 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005492 ((ctxt->context->node->parent->name[0] == ' ') ||
5493 (xmlStrEqual(ctxt->context->node->parent->name,
5494 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005495 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005496 return(ctxt->context->node->parent);
5497 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005498 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005499
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005500 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005501 }
5502 case XML_DOCUMENT_NODE:
5503 case XML_DOCUMENT_TYPE_NODE:
5504 case XML_DOCUMENT_FRAG_NODE:
5505 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005506#ifdef LIBXML_DOCB_ENABLED
5507 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005508#endif
5509 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005510 case XML_NAMESPACE_DECL: {
5511 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5512
5513 if ((ns->next != NULL) &&
5514 (ns->next->type != XML_NAMESPACE_DECL))
5515 return((xmlNodePtr) ns->next);
5516 /* Bad, how did that namespace ended-up there ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005517 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005518 }
Owen Taylor3473f882001-02-23 17:55:21 +00005519 }
5520 return(NULL);
5521 }
5522 if (cur == ctxt->context->doc->children)
5523 return((xmlNodePtr) ctxt->context->doc);
5524 if (cur == (xmlNodePtr) ctxt->context->doc)
5525 return(NULL);
5526 switch (cur->type) {
5527 case XML_ELEMENT_NODE:
5528 case XML_TEXT_NODE:
5529 case XML_CDATA_SECTION_NODE:
5530 case XML_ENTITY_REF_NODE:
5531 case XML_ENTITY_NODE:
5532 case XML_PI_NODE:
5533 case XML_COMMENT_NODE:
5534 case XML_NOTATION_NODE:
5535 case XML_DTD_NODE:
5536 case XML_ELEMENT_DECL:
5537 case XML_ATTRIBUTE_DECL:
5538 case XML_ENTITY_DECL:
5539 case XML_XINCLUDE_START:
5540 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005541 if (cur->parent == NULL)
5542 return(NULL);
5543 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005544 ((cur->parent->name[0] == ' ') ||
5545 (xmlStrEqual(cur->parent->name,
5546 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005547 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005548 return(cur->parent);
5549 case XML_ATTRIBUTE_NODE: {
5550 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5551
5552 return(att->parent);
5553 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005554 case XML_NAMESPACE_DECL: {
5555 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5556
5557 if ((ns->next != NULL) &&
5558 (ns->next->type != XML_NAMESPACE_DECL))
5559 return((xmlNodePtr) ns->next);
5560 /* Bad, how did that namespace ended-up there ? */
5561 return(NULL);
5562 }
Owen Taylor3473f882001-02-23 17:55:21 +00005563 case XML_DOCUMENT_NODE:
5564 case XML_DOCUMENT_TYPE_NODE:
5565 case XML_DOCUMENT_FRAG_NODE:
5566 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005567#ifdef LIBXML_DOCB_ENABLED
5568 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005569#endif
5570 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005571 }
5572 return(NULL);
5573}
5574
5575/**
5576 * xmlXPathNextAncestorOrSelf:
5577 * @ctxt: the XPath Parser context
5578 * @cur: the current node in the traversal
5579 *
5580 * Traversal function for the "ancestor-or-self" direction
5581 * he ancestor-or-self axis contains the context node and ancestors of
5582 * the context node in reverse document order; thus the context node is
5583 * the first node on the axis, and the context node's parent the second;
5584 * parent here is defined the same as with the parent axis.
5585 *
5586 * Returns the next element following that axis
5587 */
5588xmlNodePtr
5589xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5590 if (cur == NULL)
5591 return(ctxt->context->node);
5592 return(xmlXPathNextAncestor(ctxt, cur));
5593}
5594
5595/**
5596 * xmlXPathNextFollowingSibling:
5597 * @ctxt: the XPath Parser context
5598 * @cur: the current node in the traversal
5599 *
5600 * Traversal function for the "following-sibling" direction
5601 * The following-sibling axis contains the following siblings of the context
5602 * node in document order.
5603 *
5604 * Returns the next element following that axis
5605 */
5606xmlNodePtr
5607xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5608 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5609 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5610 return(NULL);
5611 if (cur == (xmlNodePtr) ctxt->context->doc)
5612 return(NULL);
5613 if (cur == NULL)
5614 return(ctxt->context->node->next);
5615 return(cur->next);
5616}
5617
5618/**
5619 * xmlXPathNextPrecedingSibling:
5620 * @ctxt: the XPath Parser context
5621 * @cur: the current node in the traversal
5622 *
5623 * Traversal function for the "preceding-sibling" direction
5624 * The preceding-sibling axis contains the preceding siblings of the context
5625 * node in reverse document order; the first preceding sibling is first on the
5626 * axis; the sibling preceding that node is the second on the axis and so on.
5627 *
5628 * Returns the next element following that axis
5629 */
5630xmlNodePtr
5631xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5632 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5633 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5634 return(NULL);
5635 if (cur == (xmlNodePtr) ctxt->context->doc)
5636 return(NULL);
5637 if (cur == NULL)
5638 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005639 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5640 cur = cur->prev;
5641 if (cur == NULL)
5642 return(ctxt->context->node->prev);
5643 }
Owen Taylor3473f882001-02-23 17:55:21 +00005644 return(cur->prev);
5645}
5646
5647/**
5648 * xmlXPathNextFollowing:
5649 * @ctxt: the XPath Parser context
5650 * @cur: the current node in the traversal
5651 *
5652 * Traversal function for the "following" direction
5653 * The following axis contains all nodes in the same document as the context
5654 * node that are after the context node in document order, excluding any
5655 * descendants and excluding attribute nodes and namespace nodes; the nodes
5656 * are ordered in document order
5657 *
5658 * Returns the next element following that axis
5659 */
5660xmlNodePtr
5661xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5662 if (cur != NULL && cur->children != NULL)
5663 return cur->children ;
5664 if (cur == NULL) cur = ctxt->context->node;
5665 if (cur == NULL) return(NULL) ; /* ERROR */
5666 if (cur->next != NULL) return(cur->next) ;
5667 do {
5668 cur = cur->parent;
5669 if (cur == NULL) return(NULL);
5670 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5671 if (cur->next != NULL) return(cur->next);
5672 } while (cur != NULL);
5673 return(cur);
5674}
5675
5676/*
5677 * xmlXPathIsAncestor:
5678 * @ancestor: the ancestor node
5679 * @node: the current node
5680 *
5681 * Check that @ancestor is a @node's ancestor
5682 *
5683 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5684 */
5685static int
5686xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5687 if ((ancestor == NULL) || (node == NULL)) return(0);
5688 /* nodes need to be in the same document */
5689 if (ancestor->doc != node->doc) return(0);
5690 /* avoid searching if ancestor or node is the root node */
5691 if (ancestor == (xmlNodePtr) node->doc) return(1);
5692 if (node == (xmlNodePtr) ancestor->doc) return(0);
5693 while (node->parent != NULL) {
5694 if (node->parent == ancestor)
5695 return(1);
5696 node = node->parent;
5697 }
5698 return(0);
5699}
5700
5701/**
5702 * xmlXPathNextPreceding:
5703 * @ctxt: the XPath Parser context
5704 * @cur: the current node in the traversal
5705 *
5706 * Traversal function for the "preceding" direction
5707 * the preceding axis contains all nodes in the same document as the context
5708 * node that are before the context node in document order, excluding any
5709 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5710 * ordered in reverse document order
5711 *
5712 * Returns the next element following that axis
5713 */
5714xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005715xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5716{
Owen Taylor3473f882001-02-23 17:55:21 +00005717 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005718 cur = ctxt->context->node;
5719 if (cur == NULL)
5720 return (NULL);
5721 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5722 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005723 do {
5724 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005725 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5726 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005727 }
5728
5729 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005730 if (cur == NULL)
5731 return (NULL);
5732 if (cur == ctxt->context->doc->children)
5733 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005734 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005735 return (cur);
5736}
5737
5738/**
5739 * xmlXPathNextPrecedingInternal:
5740 * @ctxt: the XPath Parser context
5741 * @cur: the current node in the traversal
5742 *
5743 * Traversal function for the "preceding" direction
5744 * the preceding axis contains all nodes in the same document as the context
5745 * node that are before the context node in document order, excluding any
5746 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5747 * ordered in reverse document order
5748 * This is a faster implementation but internal only since it requires a
5749 * state kept in the parser context: ctxt->ancestor.
5750 *
5751 * Returns the next element following that axis
5752 */
5753static xmlNodePtr
5754xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5755 xmlNodePtr cur)
5756{
5757 if (cur == NULL) {
5758 cur = ctxt->context->node;
5759 if (cur == NULL)
5760 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005761 if (cur->type == XML_NAMESPACE_DECL)
5762 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005763 ctxt->ancestor = cur->parent;
5764 }
5765 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5766 cur = cur->prev;
5767 while (cur->prev == NULL) {
5768 cur = cur->parent;
5769 if (cur == NULL)
5770 return (NULL);
5771 if (cur == ctxt->context->doc->children)
5772 return (NULL);
5773 if (cur != ctxt->ancestor)
5774 return (cur);
5775 ctxt->ancestor = cur->parent;
5776 }
5777 cur = cur->prev;
5778 while (cur->last != NULL)
5779 cur = cur->last;
5780 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005781}
5782
5783/**
5784 * xmlXPathNextNamespace:
5785 * @ctxt: the XPath Parser context
5786 * @cur: the current attribute in the traversal
5787 *
5788 * Traversal function for the "namespace" direction
5789 * the namespace axis contains the namespace nodes of the context node;
5790 * the order of nodes on this axis is implementation-defined; the axis will
5791 * be empty unless the context node is an element
5792 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005793 * We keep the XML namespace node at the end of the list.
5794 *
Owen Taylor3473f882001-02-23 17:55:21 +00005795 * Returns the next element following that axis
5796 */
5797xmlNodePtr
5798xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5799 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005800 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005801 if (ctxt->context->tmpNsList != NULL)
5802 xmlFree(ctxt->context->tmpNsList);
5803 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005804 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005805 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005806 if (ctxt->context->tmpNsList != NULL) {
5807 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5808 ctxt->context->tmpNsNr++;
5809 }
5810 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005811 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005812 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005813 if (ctxt->context->tmpNsNr > 0) {
5814 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5815 } else {
5816 if (ctxt->context->tmpNsList != NULL)
5817 xmlFree(ctxt->context->tmpNsList);
5818 ctxt->context->tmpNsList = NULL;
5819 return(NULL);
5820 }
Owen Taylor3473f882001-02-23 17:55:21 +00005821}
5822
5823/**
5824 * xmlXPathNextAttribute:
5825 * @ctxt: the XPath Parser context
5826 * @cur: the current attribute in the traversal
5827 *
5828 * Traversal function for the "attribute" direction
5829 * TODO: support DTD inherited default attributes
5830 *
5831 * Returns the next element following that axis
5832 */
5833xmlNodePtr
5834xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005835 if (ctxt->context->node == NULL)
5836 return(NULL);
5837 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5838 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005839 if (cur == NULL) {
5840 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5841 return(NULL);
5842 return((xmlNodePtr)ctxt->context->node->properties);
5843 }
5844 return((xmlNodePtr)cur->next);
5845}
5846
5847/************************************************************************
5848 * *
5849 * NodeTest Functions *
5850 * *
5851 ************************************************************************/
5852
Owen Taylor3473f882001-02-23 17:55:21 +00005853#define IS_FUNCTION 200
5854
Owen Taylor3473f882001-02-23 17:55:21 +00005855
5856/************************************************************************
5857 * *
5858 * Implicit tree core function library *
5859 * *
5860 ************************************************************************/
5861
5862/**
5863 * xmlXPathRoot:
5864 * @ctxt: the XPath Parser context
5865 *
5866 * Initialize the context to the root of the document
5867 */
5868void
5869xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5870 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5871 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5872}
5873
5874/************************************************************************
5875 * *
5876 * The explicit core function library *
5877 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5878 * *
5879 ************************************************************************/
5880
5881
5882/**
5883 * xmlXPathLastFunction:
5884 * @ctxt: the XPath Parser context
5885 * @nargs: the number of arguments
5886 *
5887 * Implement the last() XPath function
5888 * number last()
5889 * The last function returns the number of nodes in the context node list.
5890 */
5891void
5892xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5893 CHECK_ARITY(0);
5894 if (ctxt->context->contextSize >= 0) {
5895 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5896#ifdef DEBUG_EXPR
5897 xmlGenericError(xmlGenericErrorContext,
5898 "last() : %d\n", ctxt->context->contextSize);
5899#endif
5900 } else {
5901 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5902 }
5903}
5904
5905/**
5906 * xmlXPathPositionFunction:
5907 * @ctxt: the XPath Parser context
5908 * @nargs: the number of arguments
5909 *
5910 * Implement the position() XPath function
5911 * number position()
5912 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005913 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005914 * will be equal to last().
5915 */
5916void
5917xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5918 CHECK_ARITY(0);
5919 if (ctxt->context->proximityPosition >= 0) {
5920 valuePush(ctxt,
5921 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5922#ifdef DEBUG_EXPR
5923 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5924 ctxt->context->proximityPosition);
5925#endif
5926 } else {
5927 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5928 }
5929}
5930
5931/**
5932 * xmlXPathCountFunction:
5933 * @ctxt: the XPath Parser context
5934 * @nargs: the number of arguments
5935 *
5936 * Implement the count() XPath function
5937 * number count(node-set)
5938 */
5939void
5940xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5941 xmlXPathObjectPtr cur;
5942
5943 CHECK_ARITY(1);
5944 if ((ctxt->value == NULL) ||
5945 ((ctxt->value->type != XPATH_NODESET) &&
5946 (ctxt->value->type != XPATH_XSLT_TREE)))
5947 XP_ERROR(XPATH_INVALID_TYPE);
5948 cur = valuePop(ctxt);
5949
Daniel Veillard911f49a2001-04-07 15:39:35 +00005950 if ((cur == NULL) || (cur->nodesetval == NULL))
5951 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005952 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005953 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005954 } else {
5955 if ((cur->nodesetval->nodeNr != 1) ||
5956 (cur->nodesetval->nodeTab == NULL)) {
5957 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5958 } else {
5959 xmlNodePtr tmp;
5960 int i = 0;
5961
5962 tmp = cur->nodesetval->nodeTab[0];
5963 if (tmp != NULL) {
5964 tmp = tmp->children;
5965 while (tmp != NULL) {
5966 tmp = tmp->next;
5967 i++;
5968 }
5969 }
5970 valuePush(ctxt, xmlXPathNewFloat((double) i));
5971 }
5972 }
Owen Taylor3473f882001-02-23 17:55:21 +00005973 xmlXPathFreeObject(cur);
5974}
5975
5976/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005977 * xmlXPathGetElementsByIds:
5978 * @doc: the document
5979 * @ids: a whitespace separated list of IDs
5980 *
5981 * Selects elements by their unique ID.
5982 *
5983 * Returns a node-set of selected elements.
5984 */
5985static xmlNodeSetPtr
5986xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5987 xmlNodeSetPtr ret;
5988 const xmlChar *cur = ids;
5989 xmlChar *ID;
5990 xmlAttrPtr attr;
5991 xmlNodePtr elem = NULL;
5992
Daniel Veillard7a985a12003-07-06 17:57:42 +00005993 if (ids == NULL) return(NULL);
5994
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005995 ret = xmlXPathNodeSetCreate(NULL);
5996
5997 while (IS_BLANK(*cur)) cur++;
5998 while (*cur != 0) {
Daniel Veillarde209b332003-03-26 21:40:13 +00005999 while ((!IS_BLANK(*cur)) && (*cur != 0))
6000 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006001
6002 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006003 if (ID != NULL) {
6004 if (xmlValidateNCName(ID, 1) == 0) {
6005 attr = xmlGetID(doc, ID);
6006 if (attr != NULL) {
6007 if (attr->type == XML_ATTRIBUTE_NODE)
6008 elem = attr->parent;
6009 else if (attr->type == XML_ELEMENT_NODE)
6010 elem = (xmlNodePtr) attr;
6011 else
6012 elem = NULL;
6013 if (elem != NULL)
6014 xmlXPathNodeSetAdd(ret, elem);
6015 }
6016 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006017 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006018 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006019
6020 while (IS_BLANK(*cur)) cur++;
6021 ids = cur;
6022 }
6023 return(ret);
6024}
6025
6026/**
Owen Taylor3473f882001-02-23 17:55:21 +00006027 * xmlXPathIdFunction:
6028 * @ctxt: the XPath Parser context
6029 * @nargs: the number of arguments
6030 *
6031 * Implement the id() XPath function
6032 * node-set id(object)
6033 * The id function selects elements by their unique ID
6034 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6035 * then the result is the union of the result of applying id to the
6036 * string value of each of the nodes in the argument node-set. When the
6037 * argument to id is of any other type, the argument is converted to a
6038 * string as if by a call to the string function; the string is split
6039 * into a whitespace-separated list of tokens (whitespace is any sequence
6040 * of characters matching the production S); the result is a node-set
6041 * containing the elements in the same document as the context node that
6042 * have a unique ID equal to any of the tokens in the list.
6043 */
6044void
6045xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006046 xmlChar *tokens;
6047 xmlNodeSetPtr ret;
6048 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006049
6050 CHECK_ARITY(1);
6051 obj = valuePop(ctxt);
6052 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006053 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006054 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006055 int i;
6056
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006057 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006058
Daniel Veillard911f49a2001-04-07 15:39:35 +00006059 if (obj->nodesetval != NULL) {
6060 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006061 tokens =
6062 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6063 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6064 ret = xmlXPathNodeSetMerge(ret, ns);
6065 xmlXPathFreeNodeSet(ns);
6066 if (tokens != NULL)
6067 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006068 }
Owen Taylor3473f882001-02-23 17:55:21 +00006069 }
6070
6071 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006072 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006073 return;
6074 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006075 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006076
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006077 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6078 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006079
Owen Taylor3473f882001-02-23 17:55:21 +00006080 xmlXPathFreeObject(obj);
6081 return;
6082}
6083
6084/**
6085 * xmlXPathLocalNameFunction:
6086 * @ctxt: the XPath Parser context
6087 * @nargs: the number of arguments
6088 *
6089 * Implement the local-name() XPath function
6090 * string local-name(node-set?)
6091 * The local-name function returns a string containing the local part
6092 * of the name of the node in the argument node-set that is first in
6093 * document order. If the node-set is empty or the first node has no
6094 * name, an empty string is returned. If the argument is omitted it
6095 * defaults to the context node.
6096 */
6097void
6098xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6099 xmlXPathObjectPtr cur;
6100
6101 if (nargs == 0) {
6102 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6103 nargs = 1;
6104 }
6105
6106 CHECK_ARITY(1);
6107 if ((ctxt->value == NULL) ||
6108 ((ctxt->value->type != XPATH_NODESET) &&
6109 (ctxt->value->type != XPATH_XSLT_TREE)))
6110 XP_ERROR(XPATH_INVALID_TYPE);
6111 cur = valuePop(ctxt);
6112
Daniel Veillard911f49a2001-04-07 15:39:35 +00006113 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006114 valuePush(ctxt, xmlXPathNewCString(""));
6115 } else {
6116 int i = 0; /* Should be first in document order !!!!! */
6117 switch (cur->nodesetval->nodeTab[i]->type) {
6118 case XML_ELEMENT_NODE:
6119 case XML_ATTRIBUTE_NODE:
6120 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006121 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6122 valuePush(ctxt, xmlXPathNewCString(""));
6123 else
6124 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006125 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6126 break;
6127 case XML_NAMESPACE_DECL:
6128 valuePush(ctxt, xmlXPathNewString(
6129 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6130 break;
6131 default:
6132 valuePush(ctxt, xmlXPathNewCString(""));
6133 }
6134 }
6135 xmlXPathFreeObject(cur);
6136}
6137
6138/**
6139 * xmlXPathNamespaceURIFunction:
6140 * @ctxt: the XPath Parser context
6141 * @nargs: the number of arguments
6142 *
6143 * Implement the namespace-uri() XPath function
6144 * string namespace-uri(node-set?)
6145 * The namespace-uri function returns a string containing the
6146 * namespace URI of the expanded name of the node in the argument
6147 * node-set that is first in document order. If the node-set is empty,
6148 * the first node has no name, or the expanded name has no namespace
6149 * URI, an empty string is returned. If the argument is omitted it
6150 * defaults to the context node.
6151 */
6152void
6153xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6154 xmlXPathObjectPtr cur;
6155
6156 if (nargs == 0) {
6157 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6158 nargs = 1;
6159 }
6160 CHECK_ARITY(1);
6161 if ((ctxt->value == NULL) ||
6162 ((ctxt->value->type != XPATH_NODESET) &&
6163 (ctxt->value->type != XPATH_XSLT_TREE)))
6164 XP_ERROR(XPATH_INVALID_TYPE);
6165 cur = valuePop(ctxt);
6166
Daniel Veillard911f49a2001-04-07 15:39:35 +00006167 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006168 valuePush(ctxt, xmlXPathNewCString(""));
6169 } else {
6170 int i = 0; /* Should be first in document order !!!!! */
6171 switch (cur->nodesetval->nodeTab[i]->type) {
6172 case XML_ELEMENT_NODE:
6173 case XML_ATTRIBUTE_NODE:
6174 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6175 valuePush(ctxt, xmlXPathNewCString(""));
6176 else
6177 valuePush(ctxt, xmlXPathNewString(
6178 cur->nodesetval->nodeTab[i]->ns->href));
6179 break;
6180 default:
6181 valuePush(ctxt, xmlXPathNewCString(""));
6182 }
6183 }
6184 xmlXPathFreeObject(cur);
6185}
6186
6187/**
6188 * xmlXPathNameFunction:
6189 * @ctxt: the XPath Parser context
6190 * @nargs: the number of arguments
6191 *
6192 * Implement the name() XPath function
6193 * string name(node-set?)
6194 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006195 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006196 * order. The QName must represent the name with respect to the namespace
6197 * declarations in effect on the node whose name is being represented.
6198 * Typically, this will be the form in which the name occurred in the XML
6199 * source. This need not be the case if there are namespace declarations
6200 * in effect on the node that associate multiple prefixes with the same
6201 * namespace. However, an implementation may include information about
6202 * the original prefix in its representation of nodes; in this case, an
6203 * implementation can ensure that the returned string is always the same
6204 * as the QName used in the XML source. If the argument it omitted it
6205 * defaults to the context node.
6206 * Libxml keep the original prefix so the "real qualified name" used is
6207 * returned.
6208 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006209static void
Daniel Veillard04383752001-07-08 14:27:15 +00006210xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6211{
Owen Taylor3473f882001-02-23 17:55:21 +00006212 xmlXPathObjectPtr cur;
6213
6214 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006215 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6216 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006217 }
6218
6219 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006220 if ((ctxt->value == NULL) ||
6221 ((ctxt->value->type != XPATH_NODESET) &&
6222 (ctxt->value->type != XPATH_XSLT_TREE)))
6223 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006224 cur = valuePop(ctxt);
6225
Daniel Veillard911f49a2001-04-07 15:39:35 +00006226 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006227 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006228 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006229 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006230
Daniel Veillard04383752001-07-08 14:27:15 +00006231 switch (cur->nodesetval->nodeTab[i]->type) {
6232 case XML_ELEMENT_NODE:
6233 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006234 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6235 valuePush(ctxt, xmlXPathNewCString(""));
6236 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6237 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006238 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006239 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006240
Daniel Veillard652d8a92003-02-04 19:28:49 +00006241 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006242 xmlChar *fullname;
6243
6244 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6245 cur->nodesetval->nodeTab[i]->ns->prefix,
6246 NULL, 0);
6247 if (fullname == cur->nodesetval->nodeTab[i]->name)
6248 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6249 if (fullname == NULL) {
6250 XP_ERROR(XPATH_MEMORY_ERROR);
6251 }
6252 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006253 }
6254 break;
6255 default:
6256 valuePush(ctxt,
6257 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6258 xmlXPathLocalNameFunction(ctxt, 1);
6259 }
Owen Taylor3473f882001-02-23 17:55:21 +00006260 }
6261 xmlXPathFreeObject(cur);
6262}
6263
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006264
6265/**
Owen Taylor3473f882001-02-23 17:55:21 +00006266 * xmlXPathStringFunction:
6267 * @ctxt: the XPath Parser context
6268 * @nargs: the number of arguments
6269 *
6270 * Implement the string() XPath function
6271 * string string(object?)
6272 * he string function converts an object to a string as follows:
6273 * - A node-set is converted to a string by returning the value of
6274 * the node in the node-set that is first in document order.
6275 * If the node-set is empty, an empty string is returned.
6276 * - A number is converted to a string as follows
6277 * + NaN is converted to the string NaN
6278 * + positive zero is converted to the string 0
6279 * + negative zero is converted to the string 0
6280 * + positive infinity is converted to the string Infinity
6281 * + negative infinity is converted to the string -Infinity
6282 * + if the number is an integer, the number is represented in
6283 * decimal form as a Number with no decimal point and no leading
6284 * zeros, preceded by a minus sign (-) if the number is negative
6285 * + otherwise, the number is represented in decimal form as a
6286 * Number including a decimal point with at least one digit
6287 * before the decimal point and at least one digit after the
6288 * decimal point, preceded by a minus sign (-) if the number
6289 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006290 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006291 * before the decimal point; beyond the one required digit
6292 * after the decimal point there must be as many, but only as
6293 * many, more digits as are needed to uniquely distinguish the
6294 * number from all other IEEE 754 numeric values.
6295 * - The boolean false value is converted to the string false.
6296 * The boolean true value is converted to the string true.
6297 *
6298 * If the argument is omitted, it defaults to a node-set with the
6299 * context node as its only member.
6300 */
6301void
6302xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6303 xmlXPathObjectPtr cur;
6304
6305 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006306 valuePush(ctxt,
6307 xmlXPathWrapString(
6308 xmlXPathCastNodeToString(ctxt->context->node)));
6309 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006310 }
6311
6312 CHECK_ARITY(1);
6313 cur = valuePop(ctxt);
6314 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006315 cur = xmlXPathConvertString(cur);
6316 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006317}
6318
6319/**
6320 * xmlXPathStringLengthFunction:
6321 * @ctxt: the XPath Parser context
6322 * @nargs: the number of arguments
6323 *
6324 * Implement the string-length() XPath function
6325 * number string-length(string?)
6326 * The string-length returns the number of characters in the string
6327 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6328 * the context node converted to a string, in other words the value
6329 * of the context node.
6330 */
6331void
6332xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6333 xmlXPathObjectPtr cur;
6334
6335 if (nargs == 0) {
6336 if (ctxt->context->node == NULL) {
6337 valuePush(ctxt, xmlXPathNewFloat(0));
6338 } else {
6339 xmlChar *content;
6340
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006341 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006342 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006343 xmlFree(content);
6344 }
6345 return;
6346 }
6347 CHECK_ARITY(1);
6348 CAST_TO_STRING;
6349 CHECK_TYPE(XPATH_STRING);
6350 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006351 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006352 xmlXPathFreeObject(cur);
6353}
6354
6355/**
6356 * xmlXPathConcatFunction:
6357 * @ctxt: the XPath Parser context
6358 * @nargs: the number of arguments
6359 *
6360 * Implement the concat() XPath function
6361 * string concat(string, string, string*)
6362 * The concat function returns the concatenation of its arguments.
6363 */
6364void
6365xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6366 xmlXPathObjectPtr cur, newobj;
6367 xmlChar *tmp;
6368
6369 if (nargs < 2) {
6370 CHECK_ARITY(2);
6371 }
6372
6373 CAST_TO_STRING;
6374 cur = valuePop(ctxt);
6375 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6376 xmlXPathFreeObject(cur);
6377 return;
6378 }
6379 nargs--;
6380
6381 while (nargs > 0) {
6382 CAST_TO_STRING;
6383 newobj = valuePop(ctxt);
6384 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6385 xmlXPathFreeObject(newobj);
6386 xmlXPathFreeObject(cur);
6387 XP_ERROR(XPATH_INVALID_TYPE);
6388 }
6389 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6390 newobj->stringval = cur->stringval;
6391 cur->stringval = tmp;
6392
6393 xmlXPathFreeObject(newobj);
6394 nargs--;
6395 }
6396 valuePush(ctxt, cur);
6397}
6398
6399/**
6400 * xmlXPathContainsFunction:
6401 * @ctxt: the XPath Parser context
6402 * @nargs: the number of arguments
6403 *
6404 * Implement the contains() XPath function
6405 * boolean contains(string, string)
6406 * The contains function returns true if the first argument string
6407 * contains the second argument string, and otherwise returns false.
6408 */
6409void
6410xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6411 xmlXPathObjectPtr hay, needle;
6412
6413 CHECK_ARITY(2);
6414 CAST_TO_STRING;
6415 CHECK_TYPE(XPATH_STRING);
6416 needle = valuePop(ctxt);
6417 CAST_TO_STRING;
6418 hay = valuePop(ctxt);
6419 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6420 xmlXPathFreeObject(hay);
6421 xmlXPathFreeObject(needle);
6422 XP_ERROR(XPATH_INVALID_TYPE);
6423 }
6424 if (xmlStrstr(hay->stringval, needle->stringval))
6425 valuePush(ctxt, xmlXPathNewBoolean(1));
6426 else
6427 valuePush(ctxt, xmlXPathNewBoolean(0));
6428 xmlXPathFreeObject(hay);
6429 xmlXPathFreeObject(needle);
6430}
6431
6432/**
6433 * xmlXPathStartsWithFunction:
6434 * @ctxt: the XPath Parser context
6435 * @nargs: the number of arguments
6436 *
6437 * Implement the starts-with() XPath function
6438 * boolean starts-with(string, string)
6439 * The starts-with function returns true if the first argument string
6440 * starts with the second argument string, and otherwise returns false.
6441 */
6442void
6443xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6444 xmlXPathObjectPtr hay, needle;
6445 int n;
6446
6447 CHECK_ARITY(2);
6448 CAST_TO_STRING;
6449 CHECK_TYPE(XPATH_STRING);
6450 needle = valuePop(ctxt);
6451 CAST_TO_STRING;
6452 hay = valuePop(ctxt);
6453 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6454 xmlXPathFreeObject(hay);
6455 xmlXPathFreeObject(needle);
6456 XP_ERROR(XPATH_INVALID_TYPE);
6457 }
6458 n = xmlStrlen(needle->stringval);
6459 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6460 valuePush(ctxt, xmlXPathNewBoolean(0));
6461 else
6462 valuePush(ctxt, xmlXPathNewBoolean(1));
6463 xmlXPathFreeObject(hay);
6464 xmlXPathFreeObject(needle);
6465}
6466
6467/**
6468 * xmlXPathSubstringFunction:
6469 * @ctxt: the XPath Parser context
6470 * @nargs: the number of arguments
6471 *
6472 * Implement the substring() XPath function
6473 * string substring(string, number, number?)
6474 * The substring function returns the substring of the first argument
6475 * starting at the position specified in the second argument with
6476 * length specified in the third argument. For example,
6477 * substring("12345",2,3) returns "234". If the third argument is not
6478 * specified, it returns the substring starting at the position specified
6479 * in the second argument and continuing to the end of the string. For
6480 * example, substring("12345",2) returns "2345". More precisely, each
6481 * character in the string (see [3.6 Strings]) is considered to have a
6482 * numeric position: the position of the first character is 1, the position
6483 * of the second character is 2 and so on. The returned substring contains
6484 * those characters for which the position of the character is greater than
6485 * or equal to the second argument and, if the third argument is specified,
6486 * less than the sum of the second and third arguments; the comparisons
6487 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6488 * - substring("12345", 1.5, 2.6) returns "234"
6489 * - substring("12345", 0, 3) returns "12"
6490 * - substring("12345", 0 div 0, 3) returns ""
6491 * - substring("12345", 1, 0 div 0) returns ""
6492 * - substring("12345", -42, 1 div 0) returns "12345"
6493 * - substring("12345", -1 div 0, 1 div 0) returns ""
6494 */
6495void
6496xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6497 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006498 double le=0, in;
6499 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006500 xmlChar *ret;
6501
Owen Taylor3473f882001-02-23 17:55:21 +00006502 if (nargs < 2) {
6503 CHECK_ARITY(2);
6504 }
6505 if (nargs > 3) {
6506 CHECK_ARITY(3);
6507 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006508 /*
6509 * take care of possible last (position) argument
6510 */
Owen Taylor3473f882001-02-23 17:55:21 +00006511 if (nargs == 3) {
6512 CAST_TO_NUMBER;
6513 CHECK_TYPE(XPATH_NUMBER);
6514 len = valuePop(ctxt);
6515 le = len->floatval;
6516 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006517 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006518
Owen Taylor3473f882001-02-23 17:55:21 +00006519 CAST_TO_NUMBER;
6520 CHECK_TYPE(XPATH_NUMBER);
6521 start = valuePop(ctxt);
6522 in = start->floatval;
6523 xmlXPathFreeObject(start);
6524 CAST_TO_STRING;
6525 CHECK_TYPE(XPATH_STRING);
6526 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006527 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006528
Daniel Veillard97ac1312001-05-30 19:14:17 +00006529 /*
6530 * If last pos not present, calculate last position
6531 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006532 if (nargs != 3) {
6533 le = (double)m;
6534 if (in < 1.0)
6535 in = 1.0;
6536 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006537
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006538 /* Need to check for the special cases where either
6539 * the index is NaN, the length is NaN, or both
6540 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006541 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006542 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006543 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006544 * To meet the requirements of the spec, the arguments
6545 * must be converted to integer format before
6546 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006547 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006548 * First we go to integer form, rounding up
6549 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006550 */
6551 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006552 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006553
Daniel Veillard9e412302002-06-10 15:59:44 +00006554 if (xmlXPathIsInf(le) == 1) {
6555 l = m;
6556 if (i < 1)
6557 i = 1;
6558 }
6559 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6560 l = 0;
6561 else {
6562 l = (int) le;
6563 if (((double)l)+0.5 <= le) l++;
6564 }
6565
6566 /* Now we normalize inidices */
6567 i -= 1;
6568 l += i;
6569 if (i < 0)
6570 i = 0;
6571 if (l > m)
6572 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006573
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006574 /* number of chars to copy */
6575 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006576
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006577 ret = xmlUTF8Strsub(str->stringval, i, l);
6578 }
6579 else {
6580 ret = NULL;
6581 }
6582
Owen Taylor3473f882001-02-23 17:55:21 +00006583 if (ret == NULL)
6584 valuePush(ctxt, xmlXPathNewCString(""));
6585 else {
6586 valuePush(ctxt, xmlXPathNewString(ret));
6587 xmlFree(ret);
6588 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006589
Owen Taylor3473f882001-02-23 17:55:21 +00006590 xmlXPathFreeObject(str);
6591}
6592
6593/**
6594 * xmlXPathSubstringBeforeFunction:
6595 * @ctxt: the XPath Parser context
6596 * @nargs: the number of arguments
6597 *
6598 * Implement the substring-before() XPath function
6599 * string substring-before(string, string)
6600 * The substring-before function returns the substring of the first
6601 * argument string that precedes the first occurrence of the second
6602 * argument string in the first argument string, or the empty string
6603 * if the first argument string does not contain the second argument
6604 * string. For example, substring-before("1999/04/01","/") returns 1999.
6605 */
6606void
6607xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6608 xmlXPathObjectPtr str;
6609 xmlXPathObjectPtr find;
6610 xmlBufferPtr target;
6611 const xmlChar *point;
6612 int offset;
6613
6614 CHECK_ARITY(2);
6615 CAST_TO_STRING;
6616 find = valuePop(ctxt);
6617 CAST_TO_STRING;
6618 str = valuePop(ctxt);
6619
6620 target = xmlBufferCreate();
6621 if (target) {
6622 point = xmlStrstr(str->stringval, find->stringval);
6623 if (point) {
6624 offset = (int)(point - str->stringval);
6625 xmlBufferAdd(target, str->stringval, offset);
6626 }
6627 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6628 xmlBufferFree(target);
6629 }
6630
6631 xmlXPathFreeObject(str);
6632 xmlXPathFreeObject(find);
6633}
6634
6635/**
6636 * xmlXPathSubstringAfterFunction:
6637 * @ctxt: the XPath Parser context
6638 * @nargs: the number of arguments
6639 *
6640 * Implement the substring-after() XPath function
6641 * string substring-after(string, string)
6642 * The substring-after function returns the substring of the first
6643 * argument string that follows the first occurrence of the second
6644 * argument string in the first argument string, or the empty stringi
6645 * if the first argument string does not contain the second argument
6646 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6647 * and substring-after("1999/04/01","19") returns 99/04/01.
6648 */
6649void
6650xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6651 xmlXPathObjectPtr str;
6652 xmlXPathObjectPtr find;
6653 xmlBufferPtr target;
6654 const xmlChar *point;
6655 int offset;
6656
6657 CHECK_ARITY(2);
6658 CAST_TO_STRING;
6659 find = valuePop(ctxt);
6660 CAST_TO_STRING;
6661 str = valuePop(ctxt);
6662
6663 target = xmlBufferCreate();
6664 if (target) {
6665 point = xmlStrstr(str->stringval, find->stringval);
6666 if (point) {
6667 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6668 xmlBufferAdd(target, &str->stringval[offset],
6669 xmlStrlen(str->stringval) - offset);
6670 }
6671 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6672 xmlBufferFree(target);
6673 }
6674
6675 xmlXPathFreeObject(str);
6676 xmlXPathFreeObject(find);
6677}
6678
6679/**
6680 * xmlXPathNormalizeFunction:
6681 * @ctxt: the XPath Parser context
6682 * @nargs: the number of arguments
6683 *
6684 * Implement the normalize-space() XPath function
6685 * string normalize-space(string?)
6686 * The normalize-space function returns the argument string with white
6687 * space normalized by stripping leading and trailing whitespace
6688 * and replacing sequences of whitespace characters by a single
6689 * space. Whitespace characters are the same allowed by the S production
6690 * in XML. If the argument is omitted, it defaults to the context
6691 * node converted to a string, in other words the value of the context node.
6692 */
6693void
6694xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6695 xmlXPathObjectPtr obj = NULL;
6696 xmlChar *source = NULL;
6697 xmlBufferPtr target;
6698 xmlChar blank;
6699
6700 if (nargs == 0) {
6701 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006702 valuePush(ctxt,
6703 xmlXPathWrapString(
6704 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006705 nargs = 1;
6706 }
6707
6708 CHECK_ARITY(1);
6709 CAST_TO_STRING;
6710 CHECK_TYPE(XPATH_STRING);
6711 obj = valuePop(ctxt);
6712 source = obj->stringval;
6713
6714 target = xmlBufferCreate();
6715 if (target && source) {
6716
6717 /* Skip leading whitespaces */
6718 while (IS_BLANK(*source))
6719 source++;
6720
6721 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6722 blank = 0;
6723 while (*source) {
6724 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006725 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006726 } else {
6727 if (blank) {
6728 xmlBufferAdd(target, &blank, 1);
6729 blank = 0;
6730 }
6731 xmlBufferAdd(target, source, 1);
6732 }
6733 source++;
6734 }
6735
6736 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6737 xmlBufferFree(target);
6738 }
6739 xmlXPathFreeObject(obj);
6740}
6741
6742/**
6743 * xmlXPathTranslateFunction:
6744 * @ctxt: the XPath Parser context
6745 * @nargs: the number of arguments
6746 *
6747 * Implement the translate() XPath function
6748 * string translate(string, string, string)
6749 * The translate function returns the first argument string with
6750 * occurrences of characters in the second argument string replaced
6751 * by the character at the corresponding position in the third argument
6752 * string. For example, translate("bar","abc","ABC") returns the string
6753 * BAr. If there is a character in the second argument string with no
6754 * character at a corresponding position in the third argument string
6755 * (because the second argument string is longer than the third argument
6756 * string), then occurrences of that character in the first argument
6757 * string are removed. For example, translate("--aaa--","abc-","ABC")
6758 * returns "AAA". If a character occurs more than once in second
6759 * argument string, then the first occurrence determines the replacement
6760 * character. If the third argument string is longer than the second
6761 * argument string, then excess characters are ignored.
6762 */
6763void
6764xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006765 xmlXPathObjectPtr str;
6766 xmlXPathObjectPtr from;
6767 xmlXPathObjectPtr to;
6768 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006769 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006770 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006771 xmlChar *point;
6772 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006773
Daniel Veillarde043ee12001-04-16 14:08:07 +00006774 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006775
Daniel Veillarde043ee12001-04-16 14:08:07 +00006776 CAST_TO_STRING;
6777 to = valuePop(ctxt);
6778 CAST_TO_STRING;
6779 from = valuePop(ctxt);
6780 CAST_TO_STRING;
6781 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006782
Daniel Veillarde043ee12001-04-16 14:08:07 +00006783 target = xmlBufferCreate();
6784 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006785 max = xmlUTF8Strlen(to->stringval);
6786 for (cptr = str->stringval; (ch=*cptr); ) {
6787 offset = xmlUTF8Strloc(from->stringval, cptr);
6788 if (offset >= 0) {
6789 if (offset < max) {
6790 point = xmlUTF8Strpos(to->stringval, offset);
6791 if (point)
6792 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6793 }
6794 } else
6795 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6796
6797 /* Step to next character in input */
6798 cptr++;
6799 if ( ch & 0x80 ) {
6800 /* if not simple ascii, verify proper format */
6801 if ( (ch & 0xc0) != 0xc0 ) {
6802 xmlGenericError(xmlGenericErrorContext,
6803 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6804 break;
6805 }
6806 /* then skip over remaining bytes for this char */
6807 while ( (ch <<= 1) & 0x80 )
6808 if ( (*cptr++ & 0xc0) != 0x80 ) {
6809 xmlGenericError(xmlGenericErrorContext,
6810 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6811 break;
6812 }
6813 if (ch & 0x80) /* must have had error encountered */
6814 break;
6815 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006816 }
Owen Taylor3473f882001-02-23 17:55:21 +00006817 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006818 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6819 xmlBufferFree(target);
6820 xmlXPathFreeObject(str);
6821 xmlXPathFreeObject(from);
6822 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006823}
6824
6825/**
6826 * xmlXPathBooleanFunction:
6827 * @ctxt: the XPath Parser context
6828 * @nargs: the number of arguments
6829 *
6830 * Implement the boolean() XPath function
6831 * boolean boolean(object)
6832 * he boolean function converts its argument to a boolean as follows:
6833 * - a number is true if and only if it is neither positive or
6834 * negative zero nor NaN
6835 * - a node-set is true if and only if it is non-empty
6836 * - a string is true if and only if its length is non-zero
6837 */
6838void
6839xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6840 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006841
6842 CHECK_ARITY(1);
6843 cur = valuePop(ctxt);
6844 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006845 cur = xmlXPathConvertBoolean(cur);
6846 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006847}
6848
6849/**
6850 * xmlXPathNotFunction:
6851 * @ctxt: the XPath Parser context
6852 * @nargs: the number of arguments
6853 *
6854 * Implement the not() XPath function
6855 * boolean not(boolean)
6856 * The not function returns true if its argument is false,
6857 * and false otherwise.
6858 */
6859void
6860xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6861 CHECK_ARITY(1);
6862 CAST_TO_BOOLEAN;
6863 CHECK_TYPE(XPATH_BOOLEAN);
6864 ctxt->value->boolval = ! ctxt->value->boolval;
6865}
6866
6867/**
6868 * xmlXPathTrueFunction:
6869 * @ctxt: the XPath Parser context
6870 * @nargs: the number of arguments
6871 *
6872 * Implement the true() XPath function
6873 * boolean true()
6874 */
6875void
6876xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6877 CHECK_ARITY(0);
6878 valuePush(ctxt, xmlXPathNewBoolean(1));
6879}
6880
6881/**
6882 * xmlXPathFalseFunction:
6883 * @ctxt: the XPath Parser context
6884 * @nargs: the number of arguments
6885 *
6886 * Implement the false() XPath function
6887 * boolean false()
6888 */
6889void
6890xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6891 CHECK_ARITY(0);
6892 valuePush(ctxt, xmlXPathNewBoolean(0));
6893}
6894
6895/**
6896 * xmlXPathLangFunction:
6897 * @ctxt: the XPath Parser context
6898 * @nargs: the number of arguments
6899 *
6900 * Implement the lang() XPath function
6901 * boolean lang(string)
6902 * The lang function returns true or false depending on whether the
6903 * language of the context node as specified by xml:lang attributes
6904 * is the same as or is a sublanguage of the language specified by
6905 * the argument string. The language of the context node is determined
6906 * by the value of the xml:lang attribute on the context node, or, if
6907 * the context node has no xml:lang attribute, by the value of the
6908 * xml:lang attribute on the nearest ancestor of the context node that
6909 * has an xml:lang attribute. If there is no such attribute, then lang
6910 * returns false. If there is such an attribute, then lang returns
6911 * true if the attribute value is equal to the argument ignoring case,
6912 * or if there is some suffix starting with - such that the attribute
6913 * value is equal to the argument ignoring that suffix of the attribute
6914 * value and ignoring case.
6915 */
6916void
6917xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6918 xmlXPathObjectPtr val;
6919 const xmlChar *theLang;
6920 const xmlChar *lang;
6921 int ret = 0;
6922 int i;
6923
6924 CHECK_ARITY(1);
6925 CAST_TO_STRING;
6926 CHECK_TYPE(XPATH_STRING);
6927 val = valuePop(ctxt);
6928 lang = val->stringval;
6929 theLang = xmlNodeGetLang(ctxt->context->node);
6930 if ((theLang != NULL) && (lang != NULL)) {
6931 for (i = 0;lang[i] != 0;i++)
6932 if (toupper(lang[i]) != toupper(theLang[i]))
6933 goto not_equal;
6934 ret = 1;
6935 }
6936not_equal:
6937 xmlXPathFreeObject(val);
6938 valuePush(ctxt, xmlXPathNewBoolean(ret));
6939}
6940
6941/**
6942 * xmlXPathNumberFunction:
6943 * @ctxt: the XPath Parser context
6944 * @nargs: the number of arguments
6945 *
6946 * Implement the number() XPath function
6947 * number number(object?)
6948 */
6949void
6950xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6951 xmlXPathObjectPtr cur;
6952 double res;
6953
6954 if (nargs == 0) {
6955 if (ctxt->context->node == NULL) {
6956 valuePush(ctxt, xmlXPathNewFloat(0.0));
6957 } else {
6958 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6959
6960 res = xmlXPathStringEvalNumber(content);
6961 valuePush(ctxt, xmlXPathNewFloat(res));
6962 xmlFree(content);
6963 }
6964 return;
6965 }
6966
6967 CHECK_ARITY(1);
6968 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006969 cur = xmlXPathConvertNumber(cur);
6970 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006971}
6972
6973/**
6974 * xmlXPathSumFunction:
6975 * @ctxt: the XPath Parser context
6976 * @nargs: the number of arguments
6977 *
6978 * Implement the sum() XPath function
6979 * number sum(node-set)
6980 * The sum function returns the sum of the values of the nodes in
6981 * the argument node-set.
6982 */
6983void
6984xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6985 xmlXPathObjectPtr cur;
6986 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006987 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006988
6989 CHECK_ARITY(1);
6990 if ((ctxt->value == NULL) ||
6991 ((ctxt->value->type != XPATH_NODESET) &&
6992 (ctxt->value->type != XPATH_XSLT_TREE)))
6993 XP_ERROR(XPATH_INVALID_TYPE);
6994 cur = valuePop(ctxt);
6995
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006996 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006997 valuePush(ctxt, xmlXPathNewFloat(0.0));
6998 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006999 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7000 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007001 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007002 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007003 }
7004 xmlXPathFreeObject(cur);
7005}
7006
7007/**
7008 * xmlXPathFloorFunction:
7009 * @ctxt: the XPath Parser context
7010 * @nargs: the number of arguments
7011 *
7012 * Implement the floor() XPath function
7013 * number floor(number)
7014 * The floor function returns the largest (closest to positive infinity)
7015 * number that is not greater than the argument and that is an integer.
7016 */
7017void
7018xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007019 double f;
7020
Owen Taylor3473f882001-02-23 17:55:21 +00007021 CHECK_ARITY(1);
7022 CAST_TO_NUMBER;
7023 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007024
7025 f = (double)((int) ctxt->value->floatval);
7026 if (f != ctxt->value->floatval) {
7027 if (ctxt->value->floatval > 0)
7028 ctxt->value->floatval = f;
7029 else
7030 ctxt->value->floatval = f - 1;
7031 }
Owen Taylor3473f882001-02-23 17:55:21 +00007032}
7033
7034/**
7035 * xmlXPathCeilingFunction:
7036 * @ctxt: the XPath Parser context
7037 * @nargs: the number of arguments
7038 *
7039 * Implement the ceiling() XPath function
7040 * number ceiling(number)
7041 * The ceiling function returns the smallest (closest to negative infinity)
7042 * number that is not less than the argument and that is an integer.
7043 */
7044void
7045xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7046 double f;
7047
7048 CHECK_ARITY(1);
7049 CAST_TO_NUMBER;
7050 CHECK_TYPE(XPATH_NUMBER);
7051
7052#if 0
7053 ctxt->value->floatval = ceil(ctxt->value->floatval);
7054#else
7055 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007056 if (f != ctxt->value->floatval) {
7057 if (ctxt->value->floatval > 0)
7058 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007059 else {
7060 if (ctxt->value->floatval < 0 && f == 0)
7061 ctxt->value->floatval = xmlXPathNZERO;
7062 else
7063 ctxt->value->floatval = f;
7064 }
7065
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007066 }
Owen Taylor3473f882001-02-23 17:55:21 +00007067#endif
7068}
7069
7070/**
7071 * xmlXPathRoundFunction:
7072 * @ctxt: the XPath Parser context
7073 * @nargs: the number of arguments
7074 *
7075 * Implement the round() XPath function
7076 * number round(number)
7077 * The round function returns the number that is closest to the
7078 * argument and that is an integer. If there are two such numbers,
7079 * then the one that is even is returned.
7080 */
7081void
7082xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7083 double f;
7084
7085 CHECK_ARITY(1);
7086 CAST_TO_NUMBER;
7087 CHECK_TYPE(XPATH_NUMBER);
7088
Daniel Veillardcda96922001-08-21 10:56:31 +00007089 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7090 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7091 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007092 (ctxt->value->floatval == 0.0))
7093 return;
7094
Owen Taylor3473f882001-02-23 17:55:21 +00007095 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007096 if (ctxt->value->floatval < 0) {
7097 if (ctxt->value->floatval < f - 0.5)
7098 ctxt->value->floatval = f - 1;
7099 else
7100 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007101 if (ctxt->value->floatval == 0)
7102 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007103 } else {
7104 if (ctxt->value->floatval < f + 0.5)
7105 ctxt->value->floatval = f;
7106 else
7107 ctxt->value->floatval = f + 1;
7108 }
Owen Taylor3473f882001-02-23 17:55:21 +00007109}
7110
7111/************************************************************************
7112 * *
7113 * The Parser *
7114 * *
7115 ************************************************************************/
7116
7117/*
7118 * a couple of forward declarations since we use a recursive call based
7119 * implementation.
7120 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007121static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007122static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007123static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007124static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007125static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7126 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007127
7128/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007129 * xmlXPathCurrentChar:
7130 * @ctxt: the XPath parser context
7131 * @cur: pointer to the beginning of the char
7132 * @len: pointer to the length of the char read
7133 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007134 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007135 * bytes in the input buffer.
7136 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007137 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007138 */
7139
7140static int
7141xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7142 unsigned char c;
7143 unsigned int val;
7144 const xmlChar *cur;
7145
7146 if (ctxt == NULL)
7147 return(0);
7148 cur = ctxt->cur;
7149
7150 /*
7151 * We are supposed to handle UTF8, check it's valid
7152 * From rfc2044: encoding of the Unicode values on UTF-8:
7153 *
7154 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7155 * 0000 0000-0000 007F 0xxxxxxx
7156 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7157 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7158 *
7159 * Check for the 0x110000 limit too
7160 */
7161 c = *cur;
7162 if (c & 0x80) {
7163 if ((cur[1] & 0xc0) != 0x80)
7164 goto encoding_error;
7165 if ((c & 0xe0) == 0xe0) {
7166
7167 if ((cur[2] & 0xc0) != 0x80)
7168 goto encoding_error;
7169 if ((c & 0xf0) == 0xf0) {
7170 if (((c & 0xf8) != 0xf0) ||
7171 ((cur[3] & 0xc0) != 0x80))
7172 goto encoding_error;
7173 /* 4-byte code */
7174 *len = 4;
7175 val = (cur[0] & 0x7) << 18;
7176 val |= (cur[1] & 0x3f) << 12;
7177 val |= (cur[2] & 0x3f) << 6;
7178 val |= cur[3] & 0x3f;
7179 } else {
7180 /* 3-byte code */
7181 *len = 3;
7182 val = (cur[0] & 0xf) << 12;
7183 val |= (cur[1] & 0x3f) << 6;
7184 val |= cur[2] & 0x3f;
7185 }
7186 } else {
7187 /* 2-byte code */
7188 *len = 2;
7189 val = (cur[0] & 0x1f) << 6;
7190 val |= cur[1] & 0x3f;
7191 }
7192 if (!IS_CHAR(val)) {
7193 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7194 }
7195 return(val);
7196 } else {
7197 /* 1-byte code */
7198 *len = 1;
7199 return((int) *cur);
7200 }
7201encoding_error:
7202 /*
7203 * If we detect an UTF8 error that probably mean that the
7204 * input encoding didn't get properly advertized in the
7205 * declaration header. Report the error and switch the encoding
7206 * to ISO-Latin-1 (if you don't like this policy, just declare the
7207 * encoding !)
7208 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007209 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007210 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007211}
7212
7213/**
Owen Taylor3473f882001-02-23 17:55:21 +00007214 * xmlXPathParseNCName:
7215 * @ctxt: the XPath Parser context
7216 *
7217 * parse an XML namespace non qualified name.
7218 *
7219 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7220 *
7221 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7222 * CombiningChar | Extender
7223 *
7224 * Returns the namespace name or NULL
7225 */
7226
7227xmlChar *
7228xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007229 const xmlChar *in;
7230 xmlChar *ret;
7231 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007232
Daniel Veillard2156a562001-04-28 12:24:34 +00007233 /*
7234 * Accelerator for simple ASCII names
7235 */
7236 in = ctxt->cur;
7237 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7238 ((*in >= 0x41) && (*in <= 0x5A)) ||
7239 (*in == '_')) {
7240 in++;
7241 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7242 ((*in >= 0x41) && (*in <= 0x5A)) ||
7243 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007244 (*in == '_') || (*in == '.') ||
7245 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007246 in++;
7247 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7248 (*in == '[') || (*in == ']') || (*in == ':') ||
7249 (*in == '@') || (*in == '*')) {
7250 count = in - ctxt->cur;
7251 if (count == 0)
7252 return(NULL);
7253 ret = xmlStrndup(ctxt->cur, count);
7254 ctxt->cur = in;
7255 return(ret);
7256 }
7257 }
7258 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007259}
7260
Daniel Veillard2156a562001-04-28 12:24:34 +00007261
Owen Taylor3473f882001-02-23 17:55:21 +00007262/**
7263 * xmlXPathParseQName:
7264 * @ctxt: the XPath Parser context
7265 * @prefix: a xmlChar **
7266 *
7267 * parse an XML qualified name
7268 *
7269 * [NS 5] QName ::= (Prefix ':')? LocalPart
7270 *
7271 * [NS 6] Prefix ::= NCName
7272 *
7273 * [NS 7] LocalPart ::= NCName
7274 *
7275 * Returns the function returns the local part, and prefix is updated
7276 * to get the Prefix if any.
7277 */
7278
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007279static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007280xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7281 xmlChar *ret = NULL;
7282
7283 *prefix = NULL;
7284 ret = xmlXPathParseNCName(ctxt);
7285 if (CUR == ':') {
7286 *prefix = ret;
7287 NEXT;
7288 ret = xmlXPathParseNCName(ctxt);
7289 }
7290 return(ret);
7291}
7292
7293/**
7294 * xmlXPathParseName:
7295 * @ctxt: the XPath Parser context
7296 *
7297 * parse an XML name
7298 *
7299 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7300 * CombiningChar | Extender
7301 *
7302 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7303 *
7304 * Returns the namespace name or NULL
7305 */
7306
7307xmlChar *
7308xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007309 const xmlChar *in;
7310 xmlChar *ret;
7311 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007312
Daniel Veillard61d80a22001-04-27 17:13:01 +00007313 /*
7314 * Accelerator for simple ASCII names
7315 */
7316 in = ctxt->cur;
7317 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7318 ((*in >= 0x41) && (*in <= 0x5A)) ||
7319 (*in == '_') || (*in == ':')) {
7320 in++;
7321 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7322 ((*in >= 0x41) && (*in <= 0x5A)) ||
7323 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007324 (*in == '_') || (*in == '-') ||
7325 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007326 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007327 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007328 count = in - ctxt->cur;
7329 ret = xmlStrndup(ctxt->cur, count);
7330 ctxt->cur = in;
7331 return(ret);
7332 }
7333 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007334 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007335}
7336
Daniel Veillard61d80a22001-04-27 17:13:01 +00007337static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007338xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007339 xmlChar buf[XML_MAX_NAMELEN + 5];
7340 int len = 0, l;
7341 int c;
7342
7343 /*
7344 * Handler for more complex cases
7345 */
7346 c = CUR_CHAR(l);
7347 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007348 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7349 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007350 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007351 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007352 return(NULL);
7353 }
7354
7355 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7356 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7357 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007358 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007359 (IS_COMBINING(c)) ||
7360 (IS_EXTENDER(c)))) {
7361 COPY_BUF(l,buf,len,c);
7362 NEXTL(l);
7363 c = CUR_CHAR(l);
7364 if (len >= XML_MAX_NAMELEN) {
7365 /*
7366 * Okay someone managed to make a huge name, so he's ready to pay
7367 * for the processing speed.
7368 */
7369 xmlChar *buffer;
7370 int max = len * 2;
7371
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007372 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007373 if (buffer == NULL) {
7374 XP_ERROR0(XPATH_MEMORY_ERROR);
7375 }
7376 memcpy(buffer, buf, len);
7377 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7378 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007379 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007380 (IS_COMBINING(c)) ||
7381 (IS_EXTENDER(c))) {
7382 if (len + 10 > max) {
7383 max *= 2;
7384 buffer = (xmlChar *) xmlRealloc(buffer,
7385 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007386 if (buffer == NULL) {
7387 XP_ERROR0(XPATH_MEMORY_ERROR);
7388 }
7389 }
7390 COPY_BUF(l,buffer,len,c);
7391 NEXTL(l);
7392 c = CUR_CHAR(l);
7393 }
7394 buffer[len] = 0;
7395 return(buffer);
7396 }
7397 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007398 if (len == 0)
7399 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007400 return(xmlStrndup(buf, len));
7401}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007402
7403#define MAX_FRAC 20
7404
7405static double my_pow10[MAX_FRAC] = {
7406 1.0, 10.0, 100.0, 1000.0, 10000.0,
7407 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7408 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7409 100000000000000.0,
7410 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7411 1000000000000000000.0, 10000000000000000000.0
7412};
7413
Owen Taylor3473f882001-02-23 17:55:21 +00007414/**
7415 * xmlXPathStringEvalNumber:
7416 * @str: A string to scan
7417 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007418 * [30a] Float ::= Number ('e' Digits?)?
7419 *
Owen Taylor3473f882001-02-23 17:55:21 +00007420 * [30] Number ::= Digits ('.' Digits?)?
7421 * | '.' Digits
7422 * [31] Digits ::= [0-9]+
7423 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007424 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007425 * In complement of the Number expression, this function also handles
7426 * negative values : '-' Number.
7427 *
7428 * Returns the double value.
7429 */
7430double
7431xmlXPathStringEvalNumber(const xmlChar *str) {
7432 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007433 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007434 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007435 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007436 int exponent = 0;
7437 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007438#ifdef __GNUC__
7439 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007440 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007441#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007442 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007443 while (IS_BLANK(*cur)) cur++;
7444 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7445 return(xmlXPathNAN);
7446 }
7447 if (*cur == '-') {
7448 isneg = 1;
7449 cur++;
7450 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007451
7452#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007453 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007454 * tmp/temp is a workaround against a gcc compiler bug
7455 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007456 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007457 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007458 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007459 ret = ret * 10;
7460 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007461 ok = 1;
7462 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007463 temp = (double) tmp;
7464 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007465 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007466#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007467 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007468 while ((*cur >= '0') && (*cur <= '9')) {
7469 ret = ret * 10 + (*cur - '0');
7470 ok = 1;
7471 cur++;
7472 }
7473#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007474
Owen Taylor3473f882001-02-23 17:55:21 +00007475 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007476 int v, frac = 0;
7477 double fraction = 0;
7478
Owen Taylor3473f882001-02-23 17:55:21 +00007479 cur++;
7480 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7481 return(xmlXPathNAN);
7482 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007483 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7484 v = (*cur - '0');
7485 fraction = fraction * 10 + v;
7486 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007487 cur++;
7488 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007489 fraction /= my_pow10[frac];
7490 ret = ret + fraction;
7491 while ((*cur >= '0') && (*cur <= '9'))
7492 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007493 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007494 if ((*cur == 'e') || (*cur == 'E')) {
7495 cur++;
7496 if (*cur == '-') {
7497 is_exponent_negative = 1;
7498 cur++;
7499 }
7500 while ((*cur >= '0') && (*cur <= '9')) {
7501 exponent = exponent * 10 + (*cur - '0');
7502 cur++;
7503 }
7504 }
Owen Taylor3473f882001-02-23 17:55:21 +00007505 while (IS_BLANK(*cur)) cur++;
7506 if (*cur != 0) return(xmlXPathNAN);
7507 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007508 if (is_exponent_negative) exponent = -exponent;
7509 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007510 return(ret);
7511}
7512
7513/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007514 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007515 * @ctxt: the XPath Parser context
7516 *
7517 * [30] Number ::= Digits ('.' Digits?)?
7518 * | '.' Digits
7519 * [31] Digits ::= [0-9]+
7520 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007521 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007522 *
7523 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007524static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007525xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7526{
Owen Taylor3473f882001-02-23 17:55:21 +00007527 double ret = 0.0;
7528 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007529 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007530 int exponent = 0;
7531 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007532#ifdef __GNUC__
7533 unsigned long tmp = 0;
7534 double temp;
7535#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007536
7537 CHECK_ERROR;
7538 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7539 XP_ERROR(XPATH_NUMBER_ERROR);
7540 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007541#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007542 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007543 * tmp/temp is a workaround against a gcc compiler bug
7544 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007545 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007546 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007547 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007548 ret = ret * 10;
7549 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007550 ok = 1;
7551 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007552 temp = (double) tmp;
7553 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007554 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007555#else
7556 ret = 0;
7557 while ((CUR >= '0') && (CUR <= '9')) {
7558 ret = ret * 10 + (CUR - '0');
7559 ok = 1;
7560 NEXT;
7561 }
7562#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007563 if (CUR == '.') {
7564 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007565 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7566 XP_ERROR(XPATH_NUMBER_ERROR);
7567 }
7568 while ((CUR >= '0') && (CUR <= '9')) {
7569 mult /= 10;
7570 ret = ret + (CUR - '0') * mult;
7571 NEXT;
7572 }
Owen Taylor3473f882001-02-23 17:55:21 +00007573 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007574 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007575 NEXT;
7576 if (CUR == '-') {
7577 is_exponent_negative = 1;
7578 NEXT;
7579 }
7580 while ((CUR >= '0') && (CUR <= '9')) {
7581 exponent = exponent * 10 + (CUR - '0');
7582 NEXT;
7583 }
7584 if (is_exponent_negative)
7585 exponent = -exponent;
7586 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007587 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007588 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007589 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007590}
7591
7592/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007593 * xmlXPathParseLiteral:
7594 * @ctxt: the XPath Parser context
7595 *
7596 * Parse a Literal
7597 *
7598 * [29] Literal ::= '"' [^"]* '"'
7599 * | "'" [^']* "'"
7600 *
7601 * Returns the value found or NULL in case of error
7602 */
7603static xmlChar *
7604xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7605 const xmlChar *q;
7606 xmlChar *ret = NULL;
7607
7608 if (CUR == '"') {
7609 NEXT;
7610 q = CUR_PTR;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007611 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007612 NEXT;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007613 if (!IS_CHAR((unsigned int) CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007614 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7615 } else {
7616 ret = xmlStrndup(q, CUR_PTR - q);
7617 NEXT;
7618 }
7619 } else if (CUR == '\'') {
7620 NEXT;
7621 q = CUR_PTR;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007622 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007623 NEXT;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007624 if (!IS_CHAR((unsigned int) CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007625 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7626 } else {
7627 ret = xmlStrndup(q, CUR_PTR - q);
7628 NEXT;
7629 }
7630 } else {
7631 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7632 }
7633 return(ret);
7634}
7635
7636/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007637 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007638 * @ctxt: the XPath Parser context
7639 *
7640 * Parse a Literal and push it on the stack.
7641 *
7642 * [29] Literal ::= '"' [^"]* '"'
7643 * | "'" [^']* "'"
7644 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007645 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007646 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007647static void
7648xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007649 const xmlChar *q;
7650 xmlChar *ret = NULL;
7651
7652 if (CUR == '"') {
7653 NEXT;
7654 q = CUR_PTR;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007655 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007656 NEXT;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007657 if (!IS_CHAR((unsigned int) CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007658 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7659 } else {
7660 ret = xmlStrndup(q, CUR_PTR - q);
7661 NEXT;
7662 }
7663 } else if (CUR == '\'') {
7664 NEXT;
7665 q = CUR_PTR;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007666 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007667 NEXT;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007668 if (!IS_CHAR((unsigned int) CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007669 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7670 } else {
7671 ret = xmlStrndup(q, CUR_PTR - q);
7672 NEXT;
7673 }
7674 } else {
7675 XP_ERROR(XPATH_START_LITERAL_ERROR);
7676 }
7677 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007678 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7679 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007680 xmlFree(ret);
7681}
7682
7683/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007684 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007685 * @ctxt: the XPath Parser context
7686 *
7687 * Parse a VariableReference, evaluate it and push it on the stack.
7688 *
7689 * The variable bindings consist of a mapping from variable names
7690 * to variable values. The value of a variable is an object, which
7691 * of any of the types that are possible for the value of an expression,
7692 * and may also be of additional types not specified here.
7693 *
7694 * Early evaluation is possible since:
7695 * The variable bindings [...] used to evaluate a subexpression are
7696 * always the same as those used to evaluate the containing expression.
7697 *
7698 * [36] VariableReference ::= '$' QName
7699 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007700static void
7701xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007702 xmlChar *name;
7703 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007704
7705 SKIP_BLANKS;
7706 if (CUR != '$') {
7707 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7708 }
7709 NEXT;
7710 name = xmlXPathParseQName(ctxt, &prefix);
7711 if (name == NULL) {
7712 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7713 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007714 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007715 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7716 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007717 SKIP_BLANKS;
7718}
7719
7720/**
7721 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007722 * @name: a name string
7723 *
7724 * Is the name given a NodeType one.
7725 *
7726 * [38] NodeType ::= 'comment'
7727 * | 'text'
7728 * | 'processing-instruction'
7729 * | 'node'
7730 *
7731 * Returns 1 if true 0 otherwise
7732 */
7733int
7734xmlXPathIsNodeType(const xmlChar *name) {
7735 if (name == NULL)
7736 return(0);
7737
Daniel Veillard1971ee22002-01-31 20:29:19 +00007738 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007739 return(1);
7740 if (xmlStrEqual(name, BAD_CAST "text"))
7741 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007742 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007743 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007744 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007745 return(1);
7746 return(0);
7747}
7748
7749/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007750 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007751 * @ctxt: the XPath Parser context
7752 *
7753 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7754 * [17] Argument ::= Expr
7755 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007756 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007757 * pushed on the stack
7758 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007759static void
7760xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007761 xmlChar *name;
7762 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007763 int nbargs = 0;
7764
7765 name = xmlXPathParseQName(ctxt, &prefix);
7766 if (name == NULL) {
7767 XP_ERROR(XPATH_EXPR_ERROR);
7768 }
7769 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007770#ifdef DEBUG_EXPR
7771 if (prefix == NULL)
7772 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7773 name);
7774 else
7775 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7776 prefix, name);
7777#endif
7778
Owen Taylor3473f882001-02-23 17:55:21 +00007779 if (CUR != '(') {
7780 XP_ERROR(XPATH_EXPR_ERROR);
7781 }
7782 NEXT;
7783 SKIP_BLANKS;
7784
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007785 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007786 if (CUR != ')') {
7787 while (CUR != 0) {
7788 int op1 = ctxt->comp->last;
7789 ctxt->comp->last = -1;
7790 xmlXPathCompileExpr(ctxt);
7791 CHECK_ERROR;
7792 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7793 nbargs++;
7794 if (CUR == ')') break;
7795 if (CUR != ',') {
7796 XP_ERROR(XPATH_EXPR_ERROR);
7797 }
7798 NEXT;
7799 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007800 }
Owen Taylor3473f882001-02-23 17:55:21 +00007801 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007802 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7803 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007804 NEXT;
7805 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007806}
7807
7808/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007809 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007810 * @ctxt: the XPath Parser context
7811 *
7812 * [15] PrimaryExpr ::= VariableReference
7813 * | '(' Expr ')'
7814 * | Literal
7815 * | Number
7816 * | FunctionCall
7817 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007818 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007819 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007820static void
7821xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007822 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007823 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007824 else if (CUR == '(') {
7825 NEXT;
7826 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007827 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007828 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007829 if (CUR != ')') {
7830 XP_ERROR(XPATH_EXPR_ERROR);
7831 }
7832 NEXT;
7833 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007834 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007835 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007836 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007837 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007838 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007839 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007840 }
7841 SKIP_BLANKS;
7842}
7843
7844/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007845 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007846 * @ctxt: the XPath Parser context
7847 *
7848 * [20] FilterExpr ::= PrimaryExpr
7849 * | FilterExpr Predicate
7850 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007851 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007852 * Square brackets are used to filter expressions in the same way that
7853 * they are used in location paths. It is an error if the expression to
7854 * be filtered does not evaluate to a node-set. The context node list
7855 * used for evaluating the expression in square brackets is the node-set
7856 * to be filtered listed in document order.
7857 */
7858
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007859static void
7860xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7861 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007862 CHECK_ERROR;
7863 SKIP_BLANKS;
7864
7865 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007866 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007867 SKIP_BLANKS;
7868 }
7869
7870
7871}
7872
7873/**
7874 * xmlXPathScanName:
7875 * @ctxt: the XPath Parser context
7876 *
7877 * Trickery: parse an XML name but without consuming the input flow
7878 * Needed to avoid insanity in the parser state.
7879 *
7880 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7881 * CombiningChar | Extender
7882 *
7883 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7884 *
7885 * [6] Names ::= Name (S Name)*
7886 *
7887 * Returns the Name parsed or NULL
7888 */
7889
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007890static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007891xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7892 xmlChar buf[XML_MAX_NAMELEN];
7893 int len = 0;
7894
7895 SKIP_BLANKS;
7896 if (!IS_LETTER(CUR) && (CUR != '_') &&
7897 (CUR != ':')) {
7898 return(NULL);
7899 }
7900
7901 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7902 (NXT(len) == '.') || (NXT(len) == '-') ||
7903 (NXT(len) == '_') || (NXT(len) == ':') ||
7904 (IS_COMBINING(NXT(len))) ||
7905 (IS_EXTENDER(NXT(len)))) {
7906 buf[len] = NXT(len);
7907 len++;
7908 if (len >= XML_MAX_NAMELEN) {
7909 xmlGenericError(xmlGenericErrorContext,
7910 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7911 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7912 (NXT(len) == '.') || (NXT(len) == '-') ||
7913 (NXT(len) == '_') || (NXT(len) == ':') ||
7914 (IS_COMBINING(NXT(len))) ||
7915 (IS_EXTENDER(NXT(len))))
7916 len++;
7917 break;
7918 }
7919 }
7920 return(xmlStrndup(buf, len));
7921}
7922
7923/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007924 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007925 * @ctxt: the XPath Parser context
7926 *
7927 * [19] PathExpr ::= LocationPath
7928 * | FilterExpr
7929 * | FilterExpr '/' RelativeLocationPath
7930 * | FilterExpr '//' RelativeLocationPath
7931 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007932 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007933 * The / operator and // operators combine an arbitrary expression
7934 * and a relative location path. It is an error if the expression
7935 * does not evaluate to a node-set.
7936 * The / operator does composition in the same way as when / is
7937 * used in a location path. As in location paths, // is short for
7938 * /descendant-or-self::node()/.
7939 */
7940
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007941static void
7942xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007943 int lc = 1; /* Should we branch to LocationPath ? */
7944 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7945
7946 SKIP_BLANKS;
7947 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007948 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007949 lc = 0;
7950 } else if (CUR == '*') {
7951 /* relative or absolute location path */
7952 lc = 1;
7953 } else if (CUR == '/') {
7954 /* relative or absolute location path */
7955 lc = 1;
7956 } else if (CUR == '@') {
7957 /* relative abbreviated attribute location path */
7958 lc = 1;
7959 } else if (CUR == '.') {
7960 /* relative abbreviated attribute location path */
7961 lc = 1;
7962 } else {
7963 /*
7964 * Problem is finding if we have a name here whether it's:
7965 * - a nodetype
7966 * - a function call in which case it's followed by '('
7967 * - an axis in which case it's followed by ':'
7968 * - a element name
7969 * We do an a priori analysis here rather than having to
7970 * maintain parsed token content through the recursive function
7971 * calls. This looks uglier but makes the code quite easier to
7972 * read/write/debug.
7973 */
7974 SKIP_BLANKS;
7975 name = xmlXPathScanName(ctxt);
7976 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7977#ifdef DEBUG_STEP
7978 xmlGenericError(xmlGenericErrorContext,
7979 "PathExpr: Axis\n");
7980#endif
7981 lc = 1;
7982 xmlFree(name);
7983 } else if (name != NULL) {
7984 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00007985
7986
7987 while (NXT(len) != 0) {
7988 if (NXT(len) == '/') {
7989 /* element name */
7990#ifdef DEBUG_STEP
7991 xmlGenericError(xmlGenericErrorContext,
7992 "PathExpr: AbbrRelLocation\n");
7993#endif
7994 lc = 1;
7995 break;
7996 } else if (IS_BLANK(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00007997 /* ignore blanks */
7998 ;
Owen Taylor3473f882001-02-23 17:55:21 +00007999 } else if (NXT(len) == ':') {
8000#ifdef DEBUG_STEP
8001 xmlGenericError(xmlGenericErrorContext,
8002 "PathExpr: AbbrRelLocation\n");
8003#endif
8004 lc = 1;
8005 break;
8006 } else if ((NXT(len) == '(')) {
8007 /* Note Type or Function */
8008 if (xmlXPathIsNodeType(name)) {
8009#ifdef DEBUG_STEP
8010 xmlGenericError(xmlGenericErrorContext,
8011 "PathExpr: Type search\n");
8012#endif
8013 lc = 1;
8014 } else {
8015#ifdef DEBUG_STEP
8016 xmlGenericError(xmlGenericErrorContext,
8017 "PathExpr: function call\n");
8018#endif
8019 lc = 0;
8020 }
8021 break;
8022 } else if ((NXT(len) == '[')) {
8023 /* element name */
8024#ifdef DEBUG_STEP
8025 xmlGenericError(xmlGenericErrorContext,
8026 "PathExpr: AbbrRelLocation\n");
8027#endif
8028 lc = 1;
8029 break;
8030 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8031 (NXT(len) == '=')) {
8032 lc = 1;
8033 break;
8034 } else {
8035 lc = 1;
8036 break;
8037 }
8038 len++;
8039 }
8040 if (NXT(len) == 0) {
8041#ifdef DEBUG_STEP
8042 xmlGenericError(xmlGenericErrorContext,
8043 "PathExpr: AbbrRelLocation\n");
8044#endif
8045 /* element name */
8046 lc = 1;
8047 }
8048 xmlFree(name);
8049 } else {
8050 /* make sure all cases are covered explicitely */
8051 XP_ERROR(XPATH_EXPR_ERROR);
8052 }
8053 }
8054
8055 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008056 if (CUR == '/') {
8057 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8058 } else {
8059 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008060 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008061 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008062 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008063 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008064 CHECK_ERROR;
8065 if ((CUR == '/') && (NXT(1) == '/')) {
8066 SKIP(2);
8067 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008068
8069 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8070 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8071 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8072
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008073 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008074 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008075 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008076 }
8077 }
8078 SKIP_BLANKS;
8079}
8080
8081/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008082 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008083 * @ctxt: the XPath Parser context
8084 *
8085 * [18] UnionExpr ::= PathExpr
8086 * | UnionExpr '|' PathExpr
8087 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008088 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008089 */
8090
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008091static void
8092xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8093 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008094 CHECK_ERROR;
8095 SKIP_BLANKS;
8096 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008097 int op1 = ctxt->comp->last;
8098 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008099
8100 NEXT;
8101 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008102 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008103
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008104 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8105
Owen Taylor3473f882001-02-23 17:55:21 +00008106 SKIP_BLANKS;
8107 }
Owen Taylor3473f882001-02-23 17:55:21 +00008108}
8109
8110/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008111 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008112 * @ctxt: the XPath Parser context
8113 *
8114 * [27] UnaryExpr ::= UnionExpr
8115 * | '-' UnaryExpr
8116 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008117 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008118 */
8119
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008120static void
8121xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008122 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008123 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008124
8125 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008126 while (CUR == '-') {
8127 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008128 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008129 NEXT;
8130 SKIP_BLANKS;
8131 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008132
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008133 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008134 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008135 if (found) {
8136 if (minus)
8137 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8138 else
8139 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008140 }
8141}
8142
8143/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008144 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008145 * @ctxt: the XPath Parser context
8146 *
8147 * [26] MultiplicativeExpr ::= UnaryExpr
8148 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8149 * | MultiplicativeExpr 'div' UnaryExpr
8150 * | MultiplicativeExpr 'mod' UnaryExpr
8151 * [34] MultiplyOperator ::= '*'
8152 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008153 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008154 */
8155
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008156static void
8157xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8158 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008159 CHECK_ERROR;
8160 SKIP_BLANKS;
8161 while ((CUR == '*') ||
8162 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8163 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8164 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008165 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008166
8167 if (CUR == '*') {
8168 op = 0;
8169 NEXT;
8170 } else if (CUR == 'd') {
8171 op = 1;
8172 SKIP(3);
8173 } else if (CUR == 'm') {
8174 op = 2;
8175 SKIP(3);
8176 }
8177 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008178 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008179 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008180 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008181 SKIP_BLANKS;
8182 }
8183}
8184
8185/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008186 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008187 * @ctxt: the XPath Parser context
8188 *
8189 * [25] AdditiveExpr ::= MultiplicativeExpr
8190 * | AdditiveExpr '+' MultiplicativeExpr
8191 * | AdditiveExpr '-' MultiplicativeExpr
8192 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008193 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008194 */
8195
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008196static void
8197xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008198
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008199 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008200 CHECK_ERROR;
8201 SKIP_BLANKS;
8202 while ((CUR == '+') || (CUR == '-')) {
8203 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008204 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008205
8206 if (CUR == '+') plus = 1;
8207 else plus = 0;
8208 NEXT;
8209 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008210 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008211 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008212 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008213 SKIP_BLANKS;
8214 }
8215}
8216
8217/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008218 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008219 * @ctxt: the XPath Parser context
8220 *
8221 * [24] RelationalExpr ::= AdditiveExpr
8222 * | RelationalExpr '<' AdditiveExpr
8223 * | RelationalExpr '>' AdditiveExpr
8224 * | RelationalExpr '<=' AdditiveExpr
8225 * | RelationalExpr '>=' AdditiveExpr
8226 *
8227 * A <= B > C is allowed ? Answer from James, yes with
8228 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8229 * which is basically what got implemented.
8230 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008231 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008232 * on the stack
8233 */
8234
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008235static void
8236xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8237 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008238 CHECK_ERROR;
8239 SKIP_BLANKS;
8240 while ((CUR == '<') ||
8241 (CUR == '>') ||
8242 ((CUR == '<') && (NXT(1) == '=')) ||
8243 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008244 int inf, strict;
8245 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008246
8247 if (CUR == '<') inf = 1;
8248 else inf = 0;
8249 if (NXT(1) == '=') strict = 0;
8250 else strict = 1;
8251 NEXT;
8252 if (!strict) NEXT;
8253 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008254 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008255 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008256 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008257 SKIP_BLANKS;
8258 }
8259}
8260
8261/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008262 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008263 * @ctxt: the XPath Parser context
8264 *
8265 * [23] EqualityExpr ::= RelationalExpr
8266 * | EqualityExpr '=' RelationalExpr
8267 * | EqualityExpr '!=' RelationalExpr
8268 *
8269 * A != B != C is allowed ? Answer from James, yes with
8270 * (RelationalExpr = RelationalExpr) = RelationalExpr
8271 * (RelationalExpr != RelationalExpr) != RelationalExpr
8272 * which is basically what got implemented.
8273 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008274 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008275 *
8276 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008277static void
8278xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8279 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008280 CHECK_ERROR;
8281 SKIP_BLANKS;
8282 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008283 int eq;
8284 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008285
8286 if (CUR == '=') eq = 1;
8287 else eq = 0;
8288 NEXT;
8289 if (!eq) NEXT;
8290 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008291 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008292 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008293 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008294 SKIP_BLANKS;
8295 }
8296}
8297
8298/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008299 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008300 * @ctxt: the XPath Parser context
8301 *
8302 * [22] AndExpr ::= EqualityExpr
8303 * | AndExpr 'and' EqualityExpr
8304 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008305 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008306 *
8307 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008308static void
8309xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8310 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008311 CHECK_ERROR;
8312 SKIP_BLANKS;
8313 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008314 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008315 SKIP(3);
8316 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008317 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008318 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008319 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008320 SKIP_BLANKS;
8321 }
8322}
8323
8324/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008325 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008326 * @ctxt: the XPath Parser context
8327 *
8328 * [14] Expr ::= OrExpr
8329 * [21] OrExpr ::= AndExpr
8330 * | OrExpr 'or' AndExpr
8331 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008332 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008333 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008334static void
8335xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8336 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008337 CHECK_ERROR;
8338 SKIP_BLANKS;
8339 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008340 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008341 SKIP(2);
8342 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008343 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008344 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008345 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8346 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008347 SKIP_BLANKS;
8348 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008349 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8350 /* more ops could be optimized too */
8351 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8352 }
Owen Taylor3473f882001-02-23 17:55:21 +00008353}
8354
8355/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008356 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008357 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008358 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008359 *
8360 * [8] Predicate ::= '[' PredicateExpr ']'
8361 * [9] PredicateExpr ::= Expr
8362 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008363 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008364 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008365static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008366xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008367 int op1 = ctxt->comp->last;
8368
8369 SKIP_BLANKS;
8370 if (CUR != '[') {
8371 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8372 }
8373 NEXT;
8374 SKIP_BLANKS;
8375
8376 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008377 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008378 CHECK_ERROR;
8379
8380 if (CUR != ']') {
8381 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8382 }
8383
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008384 if (filter)
8385 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8386 else
8387 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008388
8389 NEXT;
8390 SKIP_BLANKS;
8391}
8392
8393/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008394 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008395 * @ctxt: the XPath Parser context
8396 * @test: pointer to a xmlXPathTestVal
8397 * @type: pointer to a xmlXPathTypeVal
8398 * @prefix: placeholder for a possible name prefix
8399 *
8400 * [7] NodeTest ::= NameTest
8401 * | NodeType '(' ')'
8402 * | 'processing-instruction' '(' Literal ')'
8403 *
8404 * [37] NameTest ::= '*'
8405 * | NCName ':' '*'
8406 * | QName
8407 * [38] NodeType ::= 'comment'
8408 * | 'text'
8409 * | 'processing-instruction'
8410 * | 'node'
8411 *
8412 * Returns the name found and update @test, @type and @prefix appropriately
8413 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008414static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008415xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8416 xmlXPathTypeVal *type, const xmlChar **prefix,
8417 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008418 int blanks;
8419
8420 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8421 STRANGE;
8422 return(NULL);
8423 }
William M. Brack78637da2003-07-31 14:47:38 +00008424 *type = (xmlXPathTypeVal) 0;
8425 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008426 *prefix = NULL;
8427 SKIP_BLANKS;
8428
8429 if ((name == NULL) && (CUR == '*')) {
8430 /*
8431 * All elements
8432 */
8433 NEXT;
8434 *test = NODE_TEST_ALL;
8435 return(NULL);
8436 }
8437
8438 if (name == NULL)
8439 name = xmlXPathParseNCName(ctxt);
8440 if (name == NULL) {
8441 XP_ERROR0(XPATH_EXPR_ERROR);
8442 }
8443
8444 blanks = IS_BLANK(CUR);
8445 SKIP_BLANKS;
8446 if (CUR == '(') {
8447 NEXT;
8448 /*
8449 * NodeType or PI search
8450 */
8451 if (xmlStrEqual(name, BAD_CAST "comment"))
8452 *type = NODE_TYPE_COMMENT;
8453 else if (xmlStrEqual(name, BAD_CAST "node"))
8454 *type = NODE_TYPE_NODE;
8455 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8456 *type = NODE_TYPE_PI;
8457 else if (xmlStrEqual(name, BAD_CAST "text"))
8458 *type = NODE_TYPE_TEXT;
8459 else {
8460 if (name != NULL)
8461 xmlFree(name);
8462 XP_ERROR0(XPATH_EXPR_ERROR);
8463 }
8464
8465 *test = NODE_TEST_TYPE;
8466
8467 SKIP_BLANKS;
8468 if (*type == NODE_TYPE_PI) {
8469 /*
8470 * Specific case: search a PI by name.
8471 */
Owen Taylor3473f882001-02-23 17:55:21 +00008472 if (name != NULL)
8473 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008474 name = NULL;
8475 if (CUR != ')') {
8476 name = xmlXPathParseLiteral(ctxt);
8477 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008478 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008479 SKIP_BLANKS;
8480 }
Owen Taylor3473f882001-02-23 17:55:21 +00008481 }
8482 if (CUR != ')') {
8483 if (name != NULL)
8484 xmlFree(name);
8485 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8486 }
8487 NEXT;
8488 return(name);
8489 }
8490 *test = NODE_TEST_NAME;
8491 if ((!blanks) && (CUR == ':')) {
8492 NEXT;
8493
8494 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008495 * Since currently the parser context don't have a
8496 * namespace list associated:
8497 * The namespace name for this prefix can be computed
8498 * only at evaluation time. The compilation is done
8499 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008500 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008501#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008502 *prefix = xmlXPathNsLookup(ctxt->context, name);
8503 if (name != NULL)
8504 xmlFree(name);
8505 if (*prefix == NULL) {
8506 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8507 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008508#else
8509 *prefix = name;
8510#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008511
8512 if (CUR == '*') {
8513 /*
8514 * All elements
8515 */
8516 NEXT;
8517 *test = NODE_TEST_ALL;
8518 return(NULL);
8519 }
8520
8521 name = xmlXPathParseNCName(ctxt);
8522 if (name == NULL) {
8523 XP_ERROR0(XPATH_EXPR_ERROR);
8524 }
8525 }
8526 return(name);
8527}
8528
8529/**
8530 * xmlXPathIsAxisName:
8531 * @name: a preparsed name token
8532 *
8533 * [6] AxisName ::= 'ancestor'
8534 * | 'ancestor-or-self'
8535 * | 'attribute'
8536 * | 'child'
8537 * | 'descendant'
8538 * | 'descendant-or-self'
8539 * | 'following'
8540 * | 'following-sibling'
8541 * | 'namespace'
8542 * | 'parent'
8543 * | 'preceding'
8544 * | 'preceding-sibling'
8545 * | 'self'
8546 *
8547 * Returns the axis or 0
8548 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008549static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008550xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008551 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008552 switch (name[0]) {
8553 case 'a':
8554 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8555 ret = AXIS_ANCESTOR;
8556 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8557 ret = AXIS_ANCESTOR_OR_SELF;
8558 if (xmlStrEqual(name, BAD_CAST "attribute"))
8559 ret = AXIS_ATTRIBUTE;
8560 break;
8561 case 'c':
8562 if (xmlStrEqual(name, BAD_CAST "child"))
8563 ret = AXIS_CHILD;
8564 break;
8565 case 'd':
8566 if (xmlStrEqual(name, BAD_CAST "descendant"))
8567 ret = AXIS_DESCENDANT;
8568 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8569 ret = AXIS_DESCENDANT_OR_SELF;
8570 break;
8571 case 'f':
8572 if (xmlStrEqual(name, BAD_CAST "following"))
8573 ret = AXIS_FOLLOWING;
8574 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8575 ret = AXIS_FOLLOWING_SIBLING;
8576 break;
8577 case 'n':
8578 if (xmlStrEqual(name, BAD_CAST "namespace"))
8579 ret = AXIS_NAMESPACE;
8580 break;
8581 case 'p':
8582 if (xmlStrEqual(name, BAD_CAST "parent"))
8583 ret = AXIS_PARENT;
8584 if (xmlStrEqual(name, BAD_CAST "preceding"))
8585 ret = AXIS_PRECEDING;
8586 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8587 ret = AXIS_PRECEDING_SIBLING;
8588 break;
8589 case 's':
8590 if (xmlStrEqual(name, BAD_CAST "self"))
8591 ret = AXIS_SELF;
8592 break;
8593 }
8594 return(ret);
8595}
8596
8597/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008598 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008599 * @ctxt: the XPath Parser context
8600 *
8601 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8602 * | AbbreviatedStep
8603 *
8604 * [12] AbbreviatedStep ::= '.' | '..'
8605 *
8606 * [5] AxisSpecifier ::= AxisName '::'
8607 * | AbbreviatedAxisSpecifier
8608 *
8609 * [13] AbbreviatedAxisSpecifier ::= '@'?
8610 *
8611 * Modified for XPtr range support as:
8612 *
8613 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8614 * | AbbreviatedStep
8615 * | 'range-to' '(' Expr ')' Predicate*
8616 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008617 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008618 * A location step of . is short for self::node(). This is
8619 * particularly useful in conjunction with //. For example, the
8620 * location path .//para is short for
8621 * self::node()/descendant-or-self::node()/child::para
8622 * and so will select all para descendant elements of the context
8623 * node.
8624 * Similarly, a location step of .. is short for parent::node().
8625 * For example, ../title is short for parent::node()/child::title
8626 * and so will select the title children of the parent of the context
8627 * node.
8628 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008629static void
8630xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008631#ifdef LIBXML_XPTR_ENABLED
8632 int rangeto = 0;
8633 int op2 = -1;
8634#endif
8635
Owen Taylor3473f882001-02-23 17:55:21 +00008636 SKIP_BLANKS;
8637 if ((CUR == '.') && (NXT(1) == '.')) {
8638 SKIP(2);
8639 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008640 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8641 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008642 } else if (CUR == '.') {
8643 NEXT;
8644 SKIP_BLANKS;
8645 } else {
8646 xmlChar *name = NULL;
8647 const xmlChar *prefix = NULL;
8648 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008649 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008650 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008651 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008652
8653 /*
8654 * The modification needed for XPointer change to the production
8655 */
8656#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008657 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008658 name = xmlXPathParseNCName(ctxt);
8659 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008660 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008661 xmlFree(name);
8662 SKIP_BLANKS;
8663 if (CUR != '(') {
8664 XP_ERROR(XPATH_EXPR_ERROR);
8665 }
8666 NEXT;
8667 SKIP_BLANKS;
8668
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008669 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008670 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008671 CHECK_ERROR;
8672
8673 SKIP_BLANKS;
8674 if (CUR != ')') {
8675 XP_ERROR(XPATH_EXPR_ERROR);
8676 }
8677 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008678 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008679 goto eval_predicates;
8680 }
8681 }
8682#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008683 if (CUR == '*') {
8684 axis = AXIS_CHILD;
8685 } else {
8686 if (name == NULL)
8687 name = xmlXPathParseNCName(ctxt);
8688 if (name != NULL) {
8689 axis = xmlXPathIsAxisName(name);
8690 if (axis != 0) {
8691 SKIP_BLANKS;
8692 if ((CUR == ':') && (NXT(1) == ':')) {
8693 SKIP(2);
8694 xmlFree(name);
8695 name = NULL;
8696 } else {
8697 /* an element name can conflict with an axis one :-\ */
8698 axis = AXIS_CHILD;
8699 }
Owen Taylor3473f882001-02-23 17:55:21 +00008700 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008701 axis = AXIS_CHILD;
8702 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008703 } else if (CUR == '@') {
8704 NEXT;
8705 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008706 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008707 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008708 }
Owen Taylor3473f882001-02-23 17:55:21 +00008709 }
8710
8711 CHECK_ERROR;
8712
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008713 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008714 if (test == 0)
8715 return;
8716
8717#ifdef DEBUG_STEP
8718 xmlGenericError(xmlGenericErrorContext,
8719 "Basis : computing new set\n");
8720#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008721
Owen Taylor3473f882001-02-23 17:55:21 +00008722#ifdef DEBUG_STEP
8723 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008724 if (ctxt->value == NULL)
8725 xmlGenericError(xmlGenericErrorContext, "no value\n");
8726 else if (ctxt->value->nodesetval == NULL)
8727 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8728 else
8729 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008730#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008731
8732eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008733 op1 = ctxt->comp->last;
8734 ctxt->comp->last = -1;
8735
Owen Taylor3473f882001-02-23 17:55:21 +00008736 SKIP_BLANKS;
8737 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008738 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008739 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008740
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008741#ifdef LIBXML_XPTR_ENABLED
8742 if (rangeto) {
8743 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8744 } else
8745#endif
8746 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8747 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008748
Owen Taylor3473f882001-02-23 17:55:21 +00008749 }
8750#ifdef DEBUG_STEP
8751 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008752 if (ctxt->value == NULL)
8753 xmlGenericError(xmlGenericErrorContext, "no value\n");
8754 else if (ctxt->value->nodesetval == NULL)
8755 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8756 else
8757 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8758 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008759#endif
8760}
8761
8762/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008763 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008764 * @ctxt: the XPath Parser context
8765 *
8766 * [3] RelativeLocationPath ::= Step
8767 * | RelativeLocationPath '/' Step
8768 * | AbbreviatedRelativeLocationPath
8769 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8770 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008771 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008772 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008773static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008774xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008775(xmlXPathParserContextPtr ctxt) {
8776 SKIP_BLANKS;
8777 if ((CUR == '/') && (NXT(1) == '/')) {
8778 SKIP(2);
8779 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008780 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8781 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008782 } else if (CUR == '/') {
8783 NEXT;
8784 SKIP_BLANKS;
8785 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008786 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008787 SKIP_BLANKS;
8788 while (CUR == '/') {
8789 if ((CUR == '/') && (NXT(1) == '/')) {
8790 SKIP(2);
8791 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008792 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008793 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008794 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008795 } else if (CUR == '/') {
8796 NEXT;
8797 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008798 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008799 }
8800 SKIP_BLANKS;
8801 }
8802}
8803
8804/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008805 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008806 * @ctxt: the XPath Parser context
8807 *
8808 * [1] LocationPath ::= RelativeLocationPath
8809 * | AbsoluteLocationPath
8810 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8811 * | AbbreviatedAbsoluteLocationPath
8812 * [10] AbbreviatedAbsoluteLocationPath ::=
8813 * '//' RelativeLocationPath
8814 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008815 * Compile a location path
8816 *
Owen Taylor3473f882001-02-23 17:55:21 +00008817 * // is short for /descendant-or-self::node()/. For example,
8818 * //para is short for /descendant-or-self::node()/child::para and
8819 * so will select any para element in the document (even a para element
8820 * that is a document element will be selected by //para since the
8821 * document element node is a child of the root node); div//para is
8822 * short for div/descendant-or-self::node()/child::para and so will
8823 * select all para descendants of div children.
8824 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008825static void
8826xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008827 SKIP_BLANKS;
8828 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008829 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008830 } else {
8831 while (CUR == '/') {
8832 if ((CUR == '/') && (NXT(1) == '/')) {
8833 SKIP(2);
8834 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008835 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8836 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008837 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008838 } else if (CUR == '/') {
8839 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008840 SKIP_BLANKS;
8841 if ((CUR != 0 ) &&
8842 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8843 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008844 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008845 }
8846 }
8847 }
8848}
8849
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008850/************************************************************************
8851 * *
8852 * XPath precompiled expression evaluation *
8853 * *
8854 ************************************************************************/
8855
Daniel Veillardf06307e2001-07-03 10:35:50 +00008856static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008857xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8858
8859/**
8860 * xmlXPathNodeCollectAndTest:
8861 * @ctxt: the XPath Parser context
8862 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008863 * @first: pointer to the first element in document order
8864 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008865 *
8866 * This is the function implementing a step: based on the current list
8867 * of nodes, it builds up a new list, looking at all nodes under that
8868 * axis and selecting them it also do the predicate filtering
8869 *
8870 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008871 *
8872 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008873 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008874static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008875xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008876 xmlXPathStepOpPtr op,
8877 xmlNodePtr * first, xmlNodePtr * last)
8878{
William M. Brack78637da2003-07-31 14:47:38 +00008879 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
8880 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
8881 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008882 const xmlChar *prefix = op->value4;
8883 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008884 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008885
8886#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008887 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008888#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008889 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008890 xmlNodeSetPtr ret, list;
8891 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008892 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008893 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008894 xmlNodePtr cur = NULL;
8895 xmlXPathObjectPtr obj;
8896 xmlNodeSetPtr nodelist;
8897 xmlNodePtr tmp;
8898
Daniel Veillardf06307e2001-07-03 10:35:50 +00008899 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008900 obj = valuePop(ctxt);
8901 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008902 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008903 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008904 URI = xmlXPathNsLookup(ctxt->context, prefix);
8905 if (URI == NULL)
8906 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008907 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008908#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008909 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008910#endif
8911 switch (axis) {
8912 case AXIS_ANCESTOR:
8913#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008914 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008915#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008916 first = NULL;
8917 next = xmlXPathNextAncestor;
8918 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008919 case AXIS_ANCESTOR_OR_SELF:
8920#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008921 xmlGenericError(xmlGenericErrorContext,
8922 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008923#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008924 first = NULL;
8925 next = xmlXPathNextAncestorOrSelf;
8926 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008927 case AXIS_ATTRIBUTE:
8928#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008929 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008930#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008931 first = NULL;
8932 last = NULL;
8933 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008934 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008935 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008936 case AXIS_CHILD:
8937#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008938 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008939#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008940 last = NULL;
8941 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008942 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008943 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008944 case AXIS_DESCENDANT:
8945#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008946 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008947#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008948 last = NULL;
8949 next = xmlXPathNextDescendant;
8950 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008951 case AXIS_DESCENDANT_OR_SELF:
8952#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008953 xmlGenericError(xmlGenericErrorContext,
8954 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008955#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008956 last = NULL;
8957 next = xmlXPathNextDescendantOrSelf;
8958 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008959 case AXIS_FOLLOWING:
8960#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008961 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008962#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008963 last = NULL;
8964 next = xmlXPathNextFollowing;
8965 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008966 case AXIS_FOLLOWING_SIBLING:
8967#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008968 xmlGenericError(xmlGenericErrorContext,
8969 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008970#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008971 last = NULL;
8972 next = xmlXPathNextFollowingSibling;
8973 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008974 case AXIS_NAMESPACE:
8975#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008976 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008977#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008978 first = NULL;
8979 last = NULL;
8980 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008981 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008982 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008983 case AXIS_PARENT:
8984#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008985 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008986#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008987 first = NULL;
8988 next = xmlXPathNextParent;
8989 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008990 case AXIS_PRECEDING:
8991#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008992 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008993#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008994 first = NULL;
8995 next = xmlXPathNextPrecedingInternal;
8996 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008997 case AXIS_PRECEDING_SIBLING:
8998#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008999 xmlGenericError(xmlGenericErrorContext,
9000 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009001#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009002 first = NULL;
9003 next = xmlXPathNextPrecedingSibling;
9004 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009005 case AXIS_SELF:
9006#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009007 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009008#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009009 first = NULL;
9010 last = NULL;
9011 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009012 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009013 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009014 }
9015 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009016 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009017
9018 nodelist = obj->nodesetval;
9019 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009020 xmlXPathFreeObject(obj);
9021 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9022 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009023 }
9024 addNode = xmlXPathNodeSetAddUnique;
9025 ret = NULL;
9026#ifdef DEBUG_STEP
9027 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009028 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009029 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009030 case NODE_TEST_NONE:
9031 xmlGenericError(xmlGenericErrorContext,
9032 " searching for none !!!\n");
9033 break;
9034 case NODE_TEST_TYPE:
9035 xmlGenericError(xmlGenericErrorContext,
9036 " searching for type %d\n", type);
9037 break;
9038 case NODE_TEST_PI:
9039 xmlGenericError(xmlGenericErrorContext,
9040 " searching for PI !!!\n");
9041 break;
9042 case NODE_TEST_ALL:
9043 xmlGenericError(xmlGenericErrorContext,
9044 " searching for *\n");
9045 break;
9046 case NODE_TEST_NS:
9047 xmlGenericError(xmlGenericErrorContext,
9048 " searching for namespace %s\n",
9049 prefix);
9050 break;
9051 case NODE_TEST_NAME:
9052 xmlGenericError(xmlGenericErrorContext,
9053 " searching for name %s\n", name);
9054 if (prefix != NULL)
9055 xmlGenericError(xmlGenericErrorContext,
9056 " with namespace %s\n", prefix);
9057 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009058 }
9059 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9060#endif
9061 /*
9062 * 2.3 Node Tests
9063 * - For the attribute axis, the principal node type is attribute.
9064 * - For the namespace axis, the principal node type is namespace.
9065 * - For other axes, the principal node type is element.
9066 *
9067 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009068 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009069 * select all element children of the context node
9070 */
9071 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009072 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009073 ctxt->context->node = nodelist->nodeTab[i];
9074
Daniel Veillardf06307e2001-07-03 10:35:50 +00009075 cur = NULL;
9076 list = xmlXPathNodeSetCreate(NULL);
9077 do {
9078 cur = next(ctxt, cur);
9079 if (cur == NULL)
9080 break;
9081 if ((first != NULL) && (*first == cur))
9082 break;
9083 if (((t % 256) == 0) &&
9084 (first != NULL) && (*first != NULL) &&
9085 (xmlXPathCmpNodes(*first, cur) >= 0))
9086 break;
9087 if ((last != NULL) && (*last == cur))
9088 break;
9089 if (((t % 256) == 0) &&
9090 (last != NULL) && (*last != NULL) &&
9091 (xmlXPathCmpNodes(cur, *last) >= 0))
9092 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009093 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009094#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009095 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9096#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009097 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009098 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009099 ctxt->context->node = tmp;
9100 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009101 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009102 if ((cur->type == type) ||
9103 ((type == NODE_TYPE_NODE) &&
9104 ((cur->type == XML_DOCUMENT_NODE) ||
9105 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9106 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009107 (cur->type == XML_NAMESPACE_DECL) ||
9108 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009109 (cur->type == XML_PI_NODE) ||
9110 (cur->type == XML_COMMENT_NODE) ||
9111 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009112 (cur->type == XML_TEXT_NODE))) ||
9113 ((type == NODE_TYPE_TEXT) &&
9114 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009115#ifdef DEBUG_STEP
9116 n++;
9117#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009118 addNode(list, cur);
9119 }
9120 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009121 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009122 if (cur->type == XML_PI_NODE) {
9123 if ((name != NULL) &&
9124 (!xmlStrEqual(name, cur->name)))
9125 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009126#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009127 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009128#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009129 addNode(list, cur);
9130 }
9131 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009132 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009133 if (axis == AXIS_ATTRIBUTE) {
9134 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009135#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009136 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009137#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009138 addNode(list, cur);
9139 }
9140 } else if (axis == AXIS_NAMESPACE) {
9141 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009142#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009143 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009144#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009145 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9146 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009147 }
9148 } else {
9149 if (cur->type == XML_ELEMENT_NODE) {
9150 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009151#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009152 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009153#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009154 addNode(list, cur);
9155 } else if ((cur->ns != NULL) &&
9156 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009157#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009158 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009159#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009160 addNode(list, cur);
9161 }
9162 }
9163 }
9164 break;
9165 case NODE_TEST_NS:{
9166 TODO;
9167 break;
9168 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009169 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009170 switch (cur->type) {
9171 case XML_ELEMENT_NODE:
9172 if (xmlStrEqual(name, cur->name)) {
9173 if (prefix == NULL) {
9174 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009175#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009176 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009177#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009178 addNode(list, cur);
9179 }
9180 } else {
9181 if ((cur->ns != NULL) &&
9182 (xmlStrEqual(URI,
9183 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009184#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009185 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009186#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009187 addNode(list, cur);
9188 }
9189 }
9190 }
9191 break;
9192 case XML_ATTRIBUTE_NODE:{
9193 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009194
Daniel Veillardf06307e2001-07-03 10:35:50 +00009195 if (xmlStrEqual(name, attr->name)) {
9196 if (prefix == NULL) {
9197 if ((attr->ns == NULL) ||
9198 (attr->ns->prefix == NULL)) {
9199#ifdef DEBUG_STEP
9200 n++;
9201#endif
9202 addNode(list,
9203 (xmlNodePtr) attr);
9204 }
9205 } else {
9206 if ((attr->ns != NULL) &&
9207 (xmlStrEqual(URI,
9208 attr->ns->
9209 href))) {
9210#ifdef DEBUG_STEP
9211 n++;
9212#endif
9213 addNode(list,
9214 (xmlNodePtr) attr);
9215 }
9216 }
9217 }
9218 break;
9219 }
9220 case XML_NAMESPACE_DECL:
9221 if (cur->type == XML_NAMESPACE_DECL) {
9222 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009223
Daniel Veillardf06307e2001-07-03 10:35:50 +00009224 if ((ns->prefix != NULL) && (name != NULL)
9225 && (xmlStrEqual(ns->prefix, name))) {
9226#ifdef DEBUG_STEP
9227 n++;
9228#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009229 xmlXPathNodeSetAddNs(list,
9230 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009231 }
9232 }
9233 break;
9234 default:
9235 break;
9236 }
9237 break;
9238 break;
9239 }
9240 } while (cur != NULL);
9241
9242 /*
9243 * If there is some predicate filtering do it now
9244 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009245 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009246 xmlXPathObjectPtr obj2;
9247
9248 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9249 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9250 CHECK_TYPE0(XPATH_NODESET);
9251 obj2 = valuePop(ctxt);
9252 list = obj2->nodesetval;
9253 obj2->nodesetval = NULL;
9254 xmlXPathFreeObject(obj2);
9255 }
9256 if (ret == NULL) {
9257 ret = list;
9258 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009259 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009260 xmlXPathFreeNodeSet(list);
9261 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009262 }
9263 ctxt->context->node = tmp;
9264#ifdef DEBUG_STEP
9265 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009266 "\nExamined %d nodes, found %d nodes at that step\n",
9267 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009268#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009269 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009270 if ((obj->boolval) && (obj->user != NULL)) {
9271 ctxt->value->boolval = 1;
9272 ctxt->value->user = obj->user;
9273 obj->user = NULL;
9274 obj->boolval = 0;
9275 }
9276 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009277 return(t);
9278}
9279
9280/**
9281 * xmlXPathNodeCollectAndTestNth:
9282 * @ctxt: the XPath Parser context
9283 * @op: the XPath precompiled step operation
9284 * @indx: the index to collect
9285 * @first: pointer to the first element in document order
9286 * @last: pointer to the last element in document order
9287 *
9288 * This is the function implementing a step: based on the current list
9289 * of nodes, it builds up a new list, looking at all nodes under that
9290 * axis and selecting them it also do the predicate filtering
9291 *
9292 * Pushes the new NodeSet resulting from the search.
9293 * Returns the number of node traversed
9294 */
9295static int
9296xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9297 xmlXPathStepOpPtr op, int indx,
9298 xmlNodePtr * first, xmlNodePtr * last)
9299{
William M. Brack78637da2003-07-31 14:47:38 +00009300 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9301 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9302 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009303 const xmlChar *prefix = op->value4;
9304 const xmlChar *name = op->value5;
9305 const xmlChar *URI = NULL;
9306 int n = 0, t = 0;
9307
9308 int i;
9309 xmlNodeSetPtr list;
9310 xmlXPathTraversalFunction next = NULL;
9311 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9312 xmlNodePtr cur = NULL;
9313 xmlXPathObjectPtr obj;
9314 xmlNodeSetPtr nodelist;
9315 xmlNodePtr tmp;
9316
9317 CHECK_TYPE0(XPATH_NODESET);
9318 obj = valuePop(ctxt);
9319 addNode = xmlXPathNodeSetAdd;
9320 if (prefix != NULL) {
9321 URI = xmlXPathNsLookup(ctxt->context, prefix);
9322 if (URI == NULL)
9323 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9324 }
9325#ifdef DEBUG_STEP_NTH
9326 xmlGenericError(xmlGenericErrorContext, "new step : ");
9327 if (first != NULL) {
9328 if (*first != NULL)
9329 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9330 (*first)->name);
9331 else
9332 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9333 }
9334 if (last != NULL) {
9335 if (*last != NULL)
9336 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9337 (*last)->name);
9338 else
9339 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9340 }
9341#endif
9342 switch (axis) {
9343 case AXIS_ANCESTOR:
9344#ifdef DEBUG_STEP_NTH
9345 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9346#endif
9347 first = NULL;
9348 next = xmlXPathNextAncestor;
9349 break;
9350 case AXIS_ANCESTOR_OR_SELF:
9351#ifdef DEBUG_STEP_NTH
9352 xmlGenericError(xmlGenericErrorContext,
9353 "axis 'ancestors-or-self' ");
9354#endif
9355 first = NULL;
9356 next = xmlXPathNextAncestorOrSelf;
9357 break;
9358 case AXIS_ATTRIBUTE:
9359#ifdef DEBUG_STEP_NTH
9360 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9361#endif
9362 first = NULL;
9363 last = NULL;
9364 next = xmlXPathNextAttribute;
9365 break;
9366 case AXIS_CHILD:
9367#ifdef DEBUG_STEP_NTH
9368 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9369#endif
9370 last = NULL;
9371 next = xmlXPathNextChild;
9372 break;
9373 case AXIS_DESCENDANT:
9374#ifdef DEBUG_STEP_NTH
9375 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9376#endif
9377 last = NULL;
9378 next = xmlXPathNextDescendant;
9379 break;
9380 case AXIS_DESCENDANT_OR_SELF:
9381#ifdef DEBUG_STEP_NTH
9382 xmlGenericError(xmlGenericErrorContext,
9383 "axis 'descendant-or-self' ");
9384#endif
9385 last = NULL;
9386 next = xmlXPathNextDescendantOrSelf;
9387 break;
9388 case AXIS_FOLLOWING:
9389#ifdef DEBUG_STEP_NTH
9390 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9391#endif
9392 last = NULL;
9393 next = xmlXPathNextFollowing;
9394 break;
9395 case AXIS_FOLLOWING_SIBLING:
9396#ifdef DEBUG_STEP_NTH
9397 xmlGenericError(xmlGenericErrorContext,
9398 "axis 'following-siblings' ");
9399#endif
9400 last = NULL;
9401 next = xmlXPathNextFollowingSibling;
9402 break;
9403 case AXIS_NAMESPACE:
9404#ifdef DEBUG_STEP_NTH
9405 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9406#endif
9407 last = NULL;
9408 first = NULL;
9409 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9410 break;
9411 case AXIS_PARENT:
9412#ifdef DEBUG_STEP_NTH
9413 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9414#endif
9415 first = NULL;
9416 next = xmlXPathNextParent;
9417 break;
9418 case AXIS_PRECEDING:
9419#ifdef DEBUG_STEP_NTH
9420 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9421#endif
9422 first = NULL;
9423 next = xmlXPathNextPrecedingInternal;
9424 break;
9425 case AXIS_PRECEDING_SIBLING:
9426#ifdef DEBUG_STEP_NTH
9427 xmlGenericError(xmlGenericErrorContext,
9428 "axis 'preceding-sibling' ");
9429#endif
9430 first = NULL;
9431 next = xmlXPathNextPrecedingSibling;
9432 break;
9433 case AXIS_SELF:
9434#ifdef DEBUG_STEP_NTH
9435 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9436#endif
9437 first = NULL;
9438 last = NULL;
9439 next = xmlXPathNextSelf;
9440 break;
9441 }
9442 if (next == NULL)
9443 return(0);
9444
9445 nodelist = obj->nodesetval;
9446 if (nodelist == NULL) {
9447 xmlXPathFreeObject(obj);
9448 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9449 return(0);
9450 }
9451 addNode = xmlXPathNodeSetAddUnique;
9452#ifdef DEBUG_STEP_NTH
9453 xmlGenericError(xmlGenericErrorContext,
9454 " context contains %d nodes\n", nodelist->nodeNr);
9455 switch (test) {
9456 case NODE_TEST_NONE:
9457 xmlGenericError(xmlGenericErrorContext,
9458 " searching for none !!!\n");
9459 break;
9460 case NODE_TEST_TYPE:
9461 xmlGenericError(xmlGenericErrorContext,
9462 " searching for type %d\n", type);
9463 break;
9464 case NODE_TEST_PI:
9465 xmlGenericError(xmlGenericErrorContext,
9466 " searching for PI !!!\n");
9467 break;
9468 case NODE_TEST_ALL:
9469 xmlGenericError(xmlGenericErrorContext,
9470 " searching for *\n");
9471 break;
9472 case NODE_TEST_NS:
9473 xmlGenericError(xmlGenericErrorContext,
9474 " searching for namespace %s\n",
9475 prefix);
9476 break;
9477 case NODE_TEST_NAME:
9478 xmlGenericError(xmlGenericErrorContext,
9479 " searching for name %s\n", name);
9480 if (prefix != NULL)
9481 xmlGenericError(xmlGenericErrorContext,
9482 " with namespace %s\n", prefix);
9483 break;
9484 }
9485 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9486#endif
9487 /*
9488 * 2.3 Node Tests
9489 * - For the attribute axis, the principal node type is attribute.
9490 * - For the namespace axis, the principal node type is namespace.
9491 * - For other axes, the principal node type is element.
9492 *
9493 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009494 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009495 * select all element children of the context node
9496 */
9497 tmp = ctxt->context->node;
9498 list = xmlXPathNodeSetCreate(NULL);
9499 for (i = 0; i < nodelist->nodeNr; i++) {
9500 ctxt->context->node = nodelist->nodeTab[i];
9501
9502 cur = NULL;
9503 n = 0;
9504 do {
9505 cur = next(ctxt, cur);
9506 if (cur == NULL)
9507 break;
9508 if ((first != NULL) && (*first == cur))
9509 break;
9510 if (((t % 256) == 0) &&
9511 (first != NULL) && (*first != NULL) &&
9512 (xmlXPathCmpNodes(*first, cur) >= 0))
9513 break;
9514 if ((last != NULL) && (*last == cur))
9515 break;
9516 if (((t % 256) == 0) &&
9517 (last != NULL) && (*last != NULL) &&
9518 (xmlXPathCmpNodes(cur, *last) >= 0))
9519 break;
9520 t++;
9521 switch (test) {
9522 case NODE_TEST_NONE:
9523 ctxt->context->node = tmp;
9524 STRANGE return(0);
9525 case NODE_TEST_TYPE:
9526 if ((cur->type == type) ||
9527 ((type == NODE_TYPE_NODE) &&
9528 ((cur->type == XML_DOCUMENT_NODE) ||
9529 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9530 (cur->type == XML_ELEMENT_NODE) ||
9531 (cur->type == XML_PI_NODE) ||
9532 (cur->type == XML_COMMENT_NODE) ||
9533 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009534 (cur->type == XML_TEXT_NODE))) ||
9535 ((type == NODE_TYPE_TEXT) &&
9536 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009537 n++;
9538 if (n == indx)
9539 addNode(list, cur);
9540 }
9541 break;
9542 case NODE_TEST_PI:
9543 if (cur->type == XML_PI_NODE) {
9544 if ((name != NULL) &&
9545 (!xmlStrEqual(name, cur->name)))
9546 break;
9547 n++;
9548 if (n == indx)
9549 addNode(list, cur);
9550 }
9551 break;
9552 case NODE_TEST_ALL:
9553 if (axis == AXIS_ATTRIBUTE) {
9554 if (cur->type == XML_ATTRIBUTE_NODE) {
9555 n++;
9556 if (n == indx)
9557 addNode(list, cur);
9558 }
9559 } else if (axis == AXIS_NAMESPACE) {
9560 if (cur->type == XML_NAMESPACE_DECL) {
9561 n++;
9562 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009563 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9564 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009565 }
9566 } else {
9567 if (cur->type == XML_ELEMENT_NODE) {
9568 if (prefix == NULL) {
9569 n++;
9570 if (n == indx)
9571 addNode(list, cur);
9572 } else if ((cur->ns != NULL) &&
9573 (xmlStrEqual(URI, cur->ns->href))) {
9574 n++;
9575 if (n == indx)
9576 addNode(list, cur);
9577 }
9578 }
9579 }
9580 break;
9581 case NODE_TEST_NS:{
9582 TODO;
9583 break;
9584 }
9585 case NODE_TEST_NAME:
9586 switch (cur->type) {
9587 case XML_ELEMENT_NODE:
9588 if (xmlStrEqual(name, cur->name)) {
9589 if (prefix == NULL) {
9590 if (cur->ns == NULL) {
9591 n++;
9592 if (n == indx)
9593 addNode(list, cur);
9594 }
9595 } else {
9596 if ((cur->ns != NULL) &&
9597 (xmlStrEqual(URI,
9598 cur->ns->href))) {
9599 n++;
9600 if (n == indx)
9601 addNode(list, cur);
9602 }
9603 }
9604 }
9605 break;
9606 case XML_ATTRIBUTE_NODE:{
9607 xmlAttrPtr attr = (xmlAttrPtr) cur;
9608
9609 if (xmlStrEqual(name, attr->name)) {
9610 if (prefix == NULL) {
9611 if ((attr->ns == NULL) ||
9612 (attr->ns->prefix == NULL)) {
9613 n++;
9614 if (n == indx)
9615 addNode(list, cur);
9616 }
9617 } else {
9618 if ((attr->ns != NULL) &&
9619 (xmlStrEqual(URI,
9620 attr->ns->
9621 href))) {
9622 n++;
9623 if (n == indx)
9624 addNode(list, cur);
9625 }
9626 }
9627 }
9628 break;
9629 }
9630 case XML_NAMESPACE_DECL:
9631 if (cur->type == XML_NAMESPACE_DECL) {
9632 xmlNsPtr ns = (xmlNsPtr) cur;
9633
9634 if ((ns->prefix != NULL) && (name != NULL)
9635 && (xmlStrEqual(ns->prefix, name))) {
9636 n++;
9637 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009638 xmlXPathNodeSetAddNs(list,
9639 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009640 }
9641 }
9642 break;
9643 default:
9644 break;
9645 }
9646 break;
9647 break;
9648 }
9649 } while (n < indx);
9650 }
9651 ctxt->context->node = tmp;
9652#ifdef DEBUG_STEP_NTH
9653 xmlGenericError(xmlGenericErrorContext,
9654 "\nExamined %d nodes, found %d nodes at that step\n",
9655 t, list->nodeNr);
9656#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009657 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009658 if ((obj->boolval) && (obj->user != NULL)) {
9659 ctxt->value->boolval = 1;
9660 ctxt->value->user = obj->user;
9661 obj->user = NULL;
9662 obj->boolval = 0;
9663 }
9664 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009665 return(t);
9666}
9667
9668/**
9669 * xmlXPathCompOpEvalFirst:
9670 * @ctxt: the XPath parser context with the compiled expression
9671 * @op: an XPath compiled operation
9672 * @first: the first elem found so far
9673 *
9674 * Evaluate the Precompiled XPath operation searching only the first
9675 * element in document order
9676 *
9677 * Returns the number of examined objects.
9678 */
9679static int
9680xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9681 xmlXPathStepOpPtr op, xmlNodePtr * first)
9682{
9683 int total = 0, cur;
9684 xmlXPathCompExprPtr comp;
9685 xmlXPathObjectPtr arg1, arg2;
9686
Daniel Veillard556c6682001-10-06 09:59:51 +00009687 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009688 comp = ctxt->comp;
9689 switch (op->op) {
9690 case XPATH_OP_END:
9691 return (0);
9692 case XPATH_OP_UNION:
9693 total =
9694 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9695 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009696 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009697 if ((ctxt->value != NULL)
9698 && (ctxt->value->type == XPATH_NODESET)
9699 && (ctxt->value->nodesetval != NULL)
9700 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9701 /*
9702 * limit tree traversing to first node in the result
9703 */
9704 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9705 *first = ctxt->value->nodesetval->nodeTab[0];
9706 }
9707 cur =
9708 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9709 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009710 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009711 CHECK_TYPE0(XPATH_NODESET);
9712 arg2 = valuePop(ctxt);
9713
9714 CHECK_TYPE0(XPATH_NODESET);
9715 arg1 = valuePop(ctxt);
9716
9717 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9718 arg2->nodesetval);
9719 valuePush(ctxt, arg1);
9720 xmlXPathFreeObject(arg2);
9721 /* optimizer */
9722 if (total > cur)
9723 xmlXPathCompSwap(op);
9724 return (total + cur);
9725 case XPATH_OP_ROOT:
9726 xmlXPathRoot(ctxt);
9727 return (0);
9728 case XPATH_OP_NODE:
9729 if (op->ch1 != -1)
9730 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009731 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009732 if (op->ch2 != -1)
9733 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009734 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009735 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9736 return (total);
9737 case XPATH_OP_RESET:
9738 if (op->ch1 != -1)
9739 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009740 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009741 if (op->ch2 != -1)
9742 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009743 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009744 ctxt->context->node = NULL;
9745 return (total);
9746 case XPATH_OP_COLLECT:{
9747 if (op->ch1 == -1)
9748 return (total);
9749
9750 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009751 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009752
9753 /*
9754 * Optimization for [n] selection where n is a number
9755 */
9756 if ((op->ch2 != -1) &&
9757 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9758 (comp->steps[op->ch2].ch1 == -1) &&
9759 (comp->steps[op->ch2].ch2 != -1) &&
9760 (comp->steps[comp->steps[op->ch2].ch2].op ==
9761 XPATH_OP_VALUE)) {
9762 xmlXPathObjectPtr val;
9763
9764 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9765 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9766 int indx = (int) val->floatval;
9767
9768 if (val->floatval == (float) indx) {
9769 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9770 first, NULL);
9771 return (total);
9772 }
9773 }
9774 }
9775 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9776 return (total);
9777 }
9778 case XPATH_OP_VALUE:
9779 valuePush(ctxt,
9780 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9781 return (0);
9782 case XPATH_OP_SORT:
9783 if (op->ch1 != -1)
9784 total +=
9785 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9786 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009787 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009788 if ((ctxt->value != NULL)
9789 && (ctxt->value->type == XPATH_NODESET)
9790 && (ctxt->value->nodesetval != NULL))
9791 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9792 return (total);
9793 default:
9794 return (xmlXPathCompOpEval(ctxt, op));
9795 }
9796}
9797
9798/**
9799 * xmlXPathCompOpEvalLast:
9800 * @ctxt: the XPath parser context with the compiled expression
9801 * @op: an XPath compiled operation
9802 * @last: the last elem found so far
9803 *
9804 * Evaluate the Precompiled XPath operation searching only the last
9805 * element in document order
9806 *
9807 * Returns the number of node traversed
9808 */
9809static int
9810xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9811 xmlNodePtr * last)
9812{
9813 int total = 0, cur;
9814 xmlXPathCompExprPtr comp;
9815 xmlXPathObjectPtr arg1, arg2;
9816
Daniel Veillard556c6682001-10-06 09:59:51 +00009817 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009818 comp = ctxt->comp;
9819 switch (op->op) {
9820 case XPATH_OP_END:
9821 return (0);
9822 case XPATH_OP_UNION:
9823 total =
9824 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009825 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009826 if ((ctxt->value != NULL)
9827 && (ctxt->value->type == XPATH_NODESET)
9828 && (ctxt->value->nodesetval != NULL)
9829 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9830 /*
9831 * limit tree traversing to first node in the result
9832 */
9833 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9834 *last =
9835 ctxt->value->nodesetval->nodeTab[ctxt->value->
9836 nodesetval->nodeNr -
9837 1];
9838 }
9839 cur =
9840 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009841 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009842 if ((ctxt->value != NULL)
9843 && (ctxt->value->type == XPATH_NODESET)
9844 && (ctxt->value->nodesetval != NULL)
9845 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9846 }
9847 CHECK_TYPE0(XPATH_NODESET);
9848 arg2 = valuePop(ctxt);
9849
9850 CHECK_TYPE0(XPATH_NODESET);
9851 arg1 = valuePop(ctxt);
9852
9853 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9854 arg2->nodesetval);
9855 valuePush(ctxt, arg1);
9856 xmlXPathFreeObject(arg2);
9857 /* optimizer */
9858 if (total > cur)
9859 xmlXPathCompSwap(op);
9860 return (total + cur);
9861 case XPATH_OP_ROOT:
9862 xmlXPathRoot(ctxt);
9863 return (0);
9864 case XPATH_OP_NODE:
9865 if (op->ch1 != -1)
9866 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009867 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009868 if (op->ch2 != -1)
9869 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009870 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009871 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9872 return (total);
9873 case XPATH_OP_RESET:
9874 if (op->ch1 != -1)
9875 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009876 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009877 if (op->ch2 != -1)
9878 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009879 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009880 ctxt->context->node = NULL;
9881 return (total);
9882 case XPATH_OP_COLLECT:{
9883 if (op->ch1 == -1)
9884 return (0);
9885
9886 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009887 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009888
9889 /*
9890 * Optimization for [n] selection where n is a number
9891 */
9892 if ((op->ch2 != -1) &&
9893 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9894 (comp->steps[op->ch2].ch1 == -1) &&
9895 (comp->steps[op->ch2].ch2 != -1) &&
9896 (comp->steps[comp->steps[op->ch2].ch2].op ==
9897 XPATH_OP_VALUE)) {
9898 xmlXPathObjectPtr val;
9899
9900 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9901 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9902 int indx = (int) val->floatval;
9903
9904 if (val->floatval == (float) indx) {
9905 total +=
9906 xmlXPathNodeCollectAndTestNth(ctxt, op,
9907 indx, NULL,
9908 last);
9909 return (total);
9910 }
9911 }
9912 }
9913 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9914 return (total);
9915 }
9916 case XPATH_OP_VALUE:
9917 valuePush(ctxt,
9918 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9919 return (0);
9920 case XPATH_OP_SORT:
9921 if (op->ch1 != -1)
9922 total +=
9923 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9924 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009925 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009926 if ((ctxt->value != NULL)
9927 && (ctxt->value->type == XPATH_NODESET)
9928 && (ctxt->value->nodesetval != NULL))
9929 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9930 return (total);
9931 default:
9932 return (xmlXPathCompOpEval(ctxt, op));
9933 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009934}
9935
Owen Taylor3473f882001-02-23 17:55:21 +00009936/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009937 * xmlXPathCompOpEval:
9938 * @ctxt: the XPath parser context with the compiled expression
9939 * @op: an XPath compiled operation
9940 *
9941 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009942 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009943 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009944static int
9945xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9946{
9947 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009948 int equal, ret;
9949 xmlXPathCompExprPtr comp;
9950 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009951 xmlNodePtr bak;
9952 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009953 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009954 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009955
Daniel Veillard556c6682001-10-06 09:59:51 +00009956 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009957 comp = ctxt->comp;
9958 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009959 case XPATH_OP_END:
9960 return (0);
9961 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009962 bakd = ctxt->context->doc;
9963 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009964 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009965 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009966 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 xmlXPathBooleanFunction(ctxt, 1);
9969 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9970 return (total);
9971 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009972 ctxt->context->doc = bakd;
9973 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009974 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009975 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009976 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009977 if (ctxt->error) {
9978 xmlXPathFreeObject(arg2);
9979 return(0);
9980 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009981 xmlXPathBooleanFunction(ctxt, 1);
9982 arg1 = valuePop(ctxt);
9983 arg1->boolval &= arg2->boolval;
9984 valuePush(ctxt, arg1);
9985 xmlXPathFreeObject(arg2);
9986 return (total);
9987 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009988 bakd = ctxt->context->doc;
9989 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009990 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009991 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009992 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009993 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009994 xmlXPathBooleanFunction(ctxt, 1);
9995 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9996 return (total);
9997 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009998 ctxt->context->doc = bakd;
9999 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010000 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010001 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010002 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010003 if (ctxt->error) {
10004 xmlXPathFreeObject(arg2);
10005 return(0);
10006 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010007 xmlXPathBooleanFunction(ctxt, 1);
10008 arg1 = valuePop(ctxt);
10009 arg1->boolval |= arg2->boolval;
10010 valuePush(ctxt, arg1);
10011 xmlXPathFreeObject(arg2);
10012 return (total);
10013 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010014 bakd = ctxt->context->doc;
10015 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010016 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010017 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010018 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010019 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010020 ctxt->context->doc = bakd;
10021 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010022 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010023 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010024 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010025 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010026 if (op->value)
10027 equal = xmlXPathEqualValues(ctxt);
10028 else
10029 equal = xmlXPathNotEqualValues(ctxt);
10030 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010031 return (total);
10032 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010033 bakd = ctxt->context->doc;
10034 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010035 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010036 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010037 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010038 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010039 ctxt->context->doc = bakd;
10040 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010041 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010042 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010043 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010044 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010045 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10046 valuePush(ctxt, xmlXPathNewBoolean(ret));
10047 return (total);
10048 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010049 bakd = ctxt->context->doc;
10050 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010051 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010052 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010053 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010054 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010055 if (op->ch2 != -1) {
10056 ctxt->context->doc = bakd;
10057 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010058 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010059 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010060 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010061 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010062 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010063 if (op->value == 0)
10064 xmlXPathSubValues(ctxt);
10065 else if (op->value == 1)
10066 xmlXPathAddValues(ctxt);
10067 else if (op->value == 2)
10068 xmlXPathValueFlipSign(ctxt);
10069 else if (op->value == 3) {
10070 CAST_TO_NUMBER;
10071 CHECK_TYPE0(XPATH_NUMBER);
10072 }
10073 return (total);
10074 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010075 bakd = ctxt->context->doc;
10076 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010077 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010078 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010079 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010080 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010081 ctxt->context->doc = bakd;
10082 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010083 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010084 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010085 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010086 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010087 if (op->value == 0)
10088 xmlXPathMultValues(ctxt);
10089 else if (op->value == 1)
10090 xmlXPathDivValues(ctxt);
10091 else if (op->value == 2)
10092 xmlXPathModValues(ctxt);
10093 return (total);
10094 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010095 bakd = ctxt->context->doc;
10096 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010097 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010098 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010099 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010100 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010101 ctxt->context->doc = bakd;
10102 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010103 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010104 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010105 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010106 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010107 CHECK_TYPE0(XPATH_NODESET);
10108 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010109
Daniel Veillardf06307e2001-07-03 10:35:50 +000010110 CHECK_TYPE0(XPATH_NODESET);
10111 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010112
Daniel Veillardf06307e2001-07-03 10:35:50 +000010113 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10114 arg2->nodesetval);
10115 valuePush(ctxt, arg1);
10116 xmlXPathFreeObject(arg2);
10117 return (total);
10118 case XPATH_OP_ROOT:
10119 xmlXPathRoot(ctxt);
10120 return (total);
10121 case XPATH_OP_NODE:
10122 if (op->ch1 != -1)
10123 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010124 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010125 if (op->ch2 != -1)
10126 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010127 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010128 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10129 return (total);
10130 case XPATH_OP_RESET:
10131 if (op->ch1 != -1)
10132 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010133 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010134 if (op->ch2 != -1)
10135 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010136 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010137 ctxt->context->node = NULL;
10138 return (total);
10139 case XPATH_OP_COLLECT:{
10140 if (op->ch1 == -1)
10141 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010142
Daniel Veillardf06307e2001-07-03 10:35:50 +000010143 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010144 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010145
Daniel Veillardf06307e2001-07-03 10:35:50 +000010146 /*
10147 * Optimization for [n] selection where n is a number
10148 */
10149 if ((op->ch2 != -1) &&
10150 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10151 (comp->steps[op->ch2].ch1 == -1) &&
10152 (comp->steps[op->ch2].ch2 != -1) &&
10153 (comp->steps[comp->steps[op->ch2].ch2].op ==
10154 XPATH_OP_VALUE)) {
10155 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010156
Daniel Veillardf06307e2001-07-03 10:35:50 +000010157 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10158 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10159 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010160
Daniel Veillardf06307e2001-07-03 10:35:50 +000010161 if (val->floatval == (float) indx) {
10162 total +=
10163 xmlXPathNodeCollectAndTestNth(ctxt, op,
10164 indx, NULL,
10165 NULL);
10166 return (total);
10167 }
10168 }
10169 }
10170 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10171 return (total);
10172 }
10173 case XPATH_OP_VALUE:
10174 valuePush(ctxt,
10175 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10176 return (total);
10177 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010178 xmlXPathObjectPtr val;
10179
Daniel Veillardf06307e2001-07-03 10:35:50 +000010180 if (op->ch1 != -1)
10181 total +=
10182 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010183 if (op->value5 == NULL) {
10184 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10185 if (val == NULL) {
10186 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10187 return(0);
10188 }
10189 valuePush(ctxt, val);
10190 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010191 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010192
Daniel Veillardf06307e2001-07-03 10:35:50 +000010193 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10194 if (URI == NULL) {
10195 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010196 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010197 op->value4, op->value5);
10198 return (total);
10199 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010200 val = xmlXPathVariableLookupNS(ctxt->context,
10201 op->value4, URI);
10202 if (val == NULL) {
10203 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10204 return(0);
10205 }
10206 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010207 }
10208 return (total);
10209 }
10210 case XPATH_OP_FUNCTION:{
10211 xmlXPathFunction func;
10212 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010213 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010214
10215 if (op->ch1 != -1)
10216 total +=
10217 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010218 if (ctxt->valueNr < op->value) {
10219 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010220 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010221 ctxt->error = XPATH_INVALID_OPERAND;
10222 return (total);
10223 }
10224 for (i = 0; i < op->value; i++)
10225 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10226 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010227 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010228 ctxt->error = XPATH_INVALID_OPERAND;
10229 return (total);
10230 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010231 if (op->cache != NULL)
10232 func = (xmlXPathFunction) op->cache;
10233 else {
10234 const xmlChar *URI = NULL;
10235
10236 if (op->value5 == NULL)
10237 func =
10238 xmlXPathFunctionLookup(ctxt->context,
10239 op->value4);
10240 else {
10241 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10242 if (URI == NULL) {
10243 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010244 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010245 op->value4, op->value5);
10246 return (total);
10247 }
10248 func = xmlXPathFunctionLookupNS(ctxt->context,
10249 op->value4, URI);
10250 }
10251 if (func == NULL) {
10252 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010253 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010254 op->value4);
10255 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010256 }
10257 op->cache = (void *) func;
10258 op->cacheURI = (void *) URI;
10259 }
10260 oldFunc = ctxt->context->function;
10261 oldFuncURI = ctxt->context->functionURI;
10262 ctxt->context->function = op->value4;
10263 ctxt->context->functionURI = op->cacheURI;
10264 func(ctxt, op->value);
10265 ctxt->context->function = oldFunc;
10266 ctxt->context->functionURI = oldFuncURI;
10267 return (total);
10268 }
10269 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010270 bakd = ctxt->context->doc;
10271 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010272 if (op->ch1 != -1)
10273 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010274 ctxt->context->doc = bakd;
10275 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010276 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010277 if (op->ch2 != -1)
10278 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010279 ctxt->context->doc = bakd;
10280 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010281 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010282 return (total);
10283 case XPATH_OP_PREDICATE:
10284 case XPATH_OP_FILTER:{
10285 xmlXPathObjectPtr res;
10286 xmlXPathObjectPtr obj, tmp;
10287 xmlNodeSetPtr newset = NULL;
10288 xmlNodeSetPtr oldset;
10289 xmlNodePtr oldnode;
10290 int i;
10291
10292 /*
10293 * Optimization for ()[1] selection i.e. the first elem
10294 */
10295 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10296 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10297 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10298 xmlXPathObjectPtr val;
10299
10300 val = comp->steps[op->ch2].value4;
10301 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10302 (val->floatval == 1.0)) {
10303 xmlNodePtr first = NULL;
10304
10305 total +=
10306 xmlXPathCompOpEvalFirst(ctxt,
10307 &comp->steps[op->ch1],
10308 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010309 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010310 /*
10311 * The nodeset should be in document order,
10312 * Keep only the first value
10313 */
10314 if ((ctxt->value != NULL) &&
10315 (ctxt->value->type == XPATH_NODESET) &&
10316 (ctxt->value->nodesetval != NULL) &&
10317 (ctxt->value->nodesetval->nodeNr > 1))
10318 ctxt->value->nodesetval->nodeNr = 1;
10319 return (total);
10320 }
10321 }
10322 /*
10323 * Optimization for ()[last()] selection i.e. the last elem
10324 */
10325 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10326 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10327 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10328 int f = comp->steps[op->ch2].ch1;
10329
10330 if ((f != -1) &&
10331 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10332 (comp->steps[f].value5 == NULL) &&
10333 (comp->steps[f].value == 0) &&
10334 (comp->steps[f].value4 != NULL) &&
10335 (xmlStrEqual
10336 (comp->steps[f].value4, BAD_CAST "last"))) {
10337 xmlNodePtr last = NULL;
10338
10339 total +=
10340 xmlXPathCompOpEvalLast(ctxt,
10341 &comp->steps[op->ch1],
10342 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010343 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010344 /*
10345 * The nodeset should be in document order,
10346 * Keep only the last value
10347 */
10348 if ((ctxt->value != NULL) &&
10349 (ctxt->value->type == XPATH_NODESET) &&
10350 (ctxt->value->nodesetval != NULL) &&
10351 (ctxt->value->nodesetval->nodeTab != NULL) &&
10352 (ctxt->value->nodesetval->nodeNr > 1)) {
10353 ctxt->value->nodesetval->nodeTab[0] =
10354 ctxt->value->nodesetval->nodeTab[ctxt->
10355 value->
10356 nodesetval->
10357 nodeNr -
10358 1];
10359 ctxt->value->nodesetval->nodeNr = 1;
10360 }
10361 return (total);
10362 }
10363 }
10364
10365 if (op->ch1 != -1)
10366 total +=
10367 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010368 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010369 if (op->ch2 == -1)
10370 return (total);
10371 if (ctxt->value == NULL)
10372 return (total);
10373
10374 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010375
10376#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010377 /*
10378 * Hum are we filtering the result of an XPointer expression
10379 */
10380 if (ctxt->value->type == XPATH_LOCATIONSET) {
10381 xmlLocationSetPtr newlocset = NULL;
10382 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010383
Daniel Veillardf06307e2001-07-03 10:35:50 +000010384 /*
10385 * Extract the old locset, and then evaluate the result of the
10386 * expression for all the element in the locset. use it to grow
10387 * up a new locset.
10388 */
10389 CHECK_TYPE0(XPATH_LOCATIONSET);
10390 obj = valuePop(ctxt);
10391 oldlocset = obj->user;
10392 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010393
Daniel Veillardf06307e2001-07-03 10:35:50 +000010394 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10395 ctxt->context->contextSize = 0;
10396 ctxt->context->proximityPosition = 0;
10397 if (op->ch2 != -1)
10398 total +=
10399 xmlXPathCompOpEval(ctxt,
10400 &comp->steps[op->ch2]);
10401 res = valuePop(ctxt);
10402 if (res != NULL)
10403 xmlXPathFreeObject(res);
10404 valuePush(ctxt, obj);
10405 CHECK_ERROR0;
10406 return (total);
10407 }
10408 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010409
Daniel Veillardf06307e2001-07-03 10:35:50 +000010410 for (i = 0; i < oldlocset->locNr; i++) {
10411 /*
10412 * Run the evaluation with a node list made of a
10413 * single item in the nodelocset.
10414 */
10415 ctxt->context->node = oldlocset->locTab[i]->user;
10416 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10417 valuePush(ctxt, tmp);
10418 ctxt->context->contextSize = oldlocset->locNr;
10419 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010420
Daniel Veillardf06307e2001-07-03 10:35:50 +000010421 if (op->ch2 != -1)
10422 total +=
10423 xmlXPathCompOpEval(ctxt,
10424 &comp->steps[op->ch2]);
10425 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010426
Daniel Veillardf06307e2001-07-03 10:35:50 +000010427 /*
10428 * The result of the evaluation need to be tested to
10429 * decided whether the filter succeeded or not
10430 */
10431 res = valuePop(ctxt);
10432 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10433 xmlXPtrLocationSetAdd(newlocset,
10434 xmlXPathObjectCopy
10435 (oldlocset->locTab[i]));
10436 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010437
Daniel Veillardf06307e2001-07-03 10:35:50 +000010438 /*
10439 * Cleanup
10440 */
10441 if (res != NULL)
10442 xmlXPathFreeObject(res);
10443 if (ctxt->value == tmp) {
10444 res = valuePop(ctxt);
10445 xmlXPathFreeObject(res);
10446 }
10447
10448 ctxt->context->node = NULL;
10449 }
10450
10451 /*
10452 * The result is used as the new evaluation locset.
10453 */
10454 xmlXPathFreeObject(obj);
10455 ctxt->context->node = NULL;
10456 ctxt->context->contextSize = -1;
10457 ctxt->context->proximityPosition = -1;
10458 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10459 ctxt->context->node = oldnode;
10460 return (total);
10461 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010462#endif /* LIBXML_XPTR_ENABLED */
10463
Daniel Veillardf06307e2001-07-03 10:35:50 +000010464 /*
10465 * Extract the old set, and then evaluate the result of the
10466 * expression for all the element in the set. use it to grow
10467 * up a new set.
10468 */
10469 CHECK_TYPE0(XPATH_NODESET);
10470 obj = valuePop(ctxt);
10471 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010472
Daniel Veillardf06307e2001-07-03 10:35:50 +000010473 oldnode = ctxt->context->node;
10474 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010475
Daniel Veillardf06307e2001-07-03 10:35:50 +000010476 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10477 ctxt->context->contextSize = 0;
10478 ctxt->context->proximityPosition = 0;
10479 if (op->ch2 != -1)
10480 total +=
10481 xmlXPathCompOpEval(ctxt,
10482 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010483 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010484 res = valuePop(ctxt);
10485 if (res != NULL)
10486 xmlXPathFreeObject(res);
10487 valuePush(ctxt, obj);
10488 ctxt->context->node = oldnode;
10489 CHECK_ERROR0;
10490 } else {
10491 /*
10492 * Initialize the new set.
10493 */
10494 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010495
Daniel Veillardf06307e2001-07-03 10:35:50 +000010496 for (i = 0; i < oldset->nodeNr; i++) {
10497 /*
10498 * Run the evaluation with a node list made of
10499 * a single item in the nodeset.
10500 */
10501 ctxt->context->node = oldset->nodeTab[i];
10502 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10503 valuePush(ctxt, tmp);
10504 ctxt->context->contextSize = oldset->nodeNr;
10505 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010506
Daniel Veillardf06307e2001-07-03 10:35:50 +000010507 if (op->ch2 != -1)
10508 total +=
10509 xmlXPathCompOpEval(ctxt,
10510 &comp->steps[op->ch2]);
10511 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010512
Daniel Veillardf06307e2001-07-03 10:35:50 +000010513 /*
10514 * The result of the evaluation need to be tested to
10515 * decided whether the filter succeeded or not
10516 */
10517 res = valuePop(ctxt);
10518 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10519 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10520 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010521
Daniel Veillardf06307e2001-07-03 10:35:50 +000010522 /*
10523 * Cleanup
10524 */
10525 if (res != NULL)
10526 xmlXPathFreeObject(res);
10527 if (ctxt->value == tmp) {
10528 res = valuePop(ctxt);
10529 xmlXPathFreeObject(res);
10530 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010531
Daniel Veillardf06307e2001-07-03 10:35:50 +000010532 ctxt->context->node = NULL;
10533 }
10534
10535 /*
10536 * The result is used as the new evaluation set.
10537 */
10538 xmlXPathFreeObject(obj);
10539 ctxt->context->node = NULL;
10540 ctxt->context->contextSize = -1;
10541 ctxt->context->proximityPosition = -1;
10542 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10543 }
10544 ctxt->context->node = oldnode;
10545 return (total);
10546 }
10547 case XPATH_OP_SORT:
10548 if (op->ch1 != -1)
10549 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010550 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010551 if ((ctxt->value != NULL) &&
10552 (ctxt->value->type == XPATH_NODESET) &&
10553 (ctxt->value->nodesetval != NULL))
10554 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10555 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010556#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010557 case XPATH_OP_RANGETO:{
10558 xmlXPathObjectPtr range;
10559 xmlXPathObjectPtr res, obj;
10560 xmlXPathObjectPtr tmp;
10561 xmlLocationSetPtr newset = NULL;
10562 xmlNodeSetPtr oldset;
10563 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010564
Daniel Veillardf06307e2001-07-03 10:35:50 +000010565 if (op->ch1 != -1)
10566 total +=
10567 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10568 if (op->ch2 == -1)
10569 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010570
Daniel Veillardf06307e2001-07-03 10:35:50 +000010571 CHECK_TYPE0(XPATH_NODESET);
10572 obj = valuePop(ctxt);
10573 oldset = obj->nodesetval;
10574 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010575
Daniel Veillardf06307e2001-07-03 10:35:50 +000010576 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010577
Daniel Veillardf06307e2001-07-03 10:35:50 +000010578 if (oldset != NULL) {
10579 for (i = 0; i < oldset->nodeNr; i++) {
10580 /*
10581 * Run the evaluation with a node list made of a single item
10582 * in the nodeset.
10583 */
10584 ctxt->context->node = oldset->nodeTab[i];
10585 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10586 valuePush(ctxt, tmp);
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 /*
10595 * The result of the evaluation need to be tested to
10596 * decided whether the filter succeeded or not
10597 */
10598 res = valuePop(ctxt);
10599 range =
10600 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10601 res);
10602 if (range != NULL) {
10603 xmlXPtrLocationSetAdd(newset, range);
10604 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010605
Daniel Veillardf06307e2001-07-03 10:35:50 +000010606 /*
10607 * Cleanup
10608 */
10609 if (res != NULL)
10610 xmlXPathFreeObject(res);
10611 if (ctxt->value == tmp) {
10612 res = valuePop(ctxt);
10613 xmlXPathFreeObject(res);
10614 }
10615
10616 ctxt->context->node = NULL;
10617 }
10618 }
10619
10620 /*
10621 * The result is used as the new evaluation set.
10622 */
10623 xmlXPathFreeObject(obj);
10624 ctxt->context->node = NULL;
10625 ctxt->context->contextSize = -1;
10626 ctxt->context->proximityPosition = -1;
10627 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10628 return (total);
10629 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010630#endif /* LIBXML_XPTR_ENABLED */
10631 }
10632 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010633 "XPath: unknown precompiled operation %d\n", op->op);
10634 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010635}
10636
10637/**
10638 * xmlXPathRunEval:
10639 * @ctxt: the XPath parser context with the compiled expression
10640 *
10641 * Evaluate the Precompiled XPath expression in the given context.
10642 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010643static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010644xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10645 xmlXPathCompExprPtr comp;
10646
10647 if ((ctxt == NULL) || (ctxt->comp == NULL))
10648 return;
10649
10650 if (ctxt->valueTab == NULL) {
10651 /* Allocate the value stack */
10652 ctxt->valueTab = (xmlXPathObjectPtr *)
10653 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10654 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010655 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010656 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010657 }
10658 ctxt->valueNr = 0;
10659 ctxt->valueMax = 10;
10660 ctxt->value = NULL;
10661 }
10662 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010663 if(comp->last < 0) {
10664 xmlGenericError(xmlGenericErrorContext,
10665 "xmlXPathRunEval: last is less than zero\n");
10666 return;
10667 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010668 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10669}
10670
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010671/************************************************************************
10672 * *
10673 * Public interfaces *
10674 * *
10675 ************************************************************************/
10676
10677/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010678 * xmlXPathEvalPredicate:
10679 * @ctxt: the XPath context
10680 * @res: the Predicate Expression evaluation result
10681 *
10682 * Evaluate a predicate result for the current node.
10683 * A PredicateExpr is evaluated by evaluating the Expr and converting
10684 * the result to a boolean. If the result is a number, the result will
10685 * be converted to true if the number is equal to the position of the
10686 * context node in the context node list (as returned by the position
10687 * function) and will be converted to false otherwise; if the result
10688 * is not a number, then the result will be converted as if by a call
10689 * to the boolean function.
10690 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010691 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010692 */
10693int
10694xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10695 if (res == NULL) return(0);
10696 switch (res->type) {
10697 case XPATH_BOOLEAN:
10698 return(res->boolval);
10699 case XPATH_NUMBER:
10700 return(res->floatval == ctxt->proximityPosition);
10701 case XPATH_NODESET:
10702 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010703 if (res->nodesetval == NULL)
10704 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010705 return(res->nodesetval->nodeNr != 0);
10706 case XPATH_STRING:
10707 return((res->stringval != NULL) &&
10708 (xmlStrlen(res->stringval) != 0));
10709 default:
10710 STRANGE
10711 }
10712 return(0);
10713}
10714
10715/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010716 * xmlXPathEvaluatePredicateResult:
10717 * @ctxt: the XPath Parser context
10718 * @res: the Predicate Expression evaluation result
10719 *
10720 * Evaluate a predicate result for the current node.
10721 * A PredicateExpr is evaluated by evaluating the Expr and converting
10722 * the result to a boolean. If the result is a number, the result will
10723 * be converted to true if the number is equal to the position of the
10724 * context node in the context node list (as returned by the position
10725 * function) and will be converted to false otherwise; if the result
10726 * is not a number, then the result will be converted as if by a call
10727 * to the boolean function.
10728 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010729 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010730 */
10731int
10732xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10733 xmlXPathObjectPtr res) {
10734 if (res == NULL) return(0);
10735 switch (res->type) {
10736 case XPATH_BOOLEAN:
10737 return(res->boolval);
10738 case XPATH_NUMBER:
10739 return(res->floatval == ctxt->context->proximityPosition);
10740 case XPATH_NODESET:
10741 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010742 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010743 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010744 return(res->nodesetval->nodeNr != 0);
10745 case XPATH_STRING:
10746 return((res->stringval != NULL) &&
10747 (xmlStrlen(res->stringval) != 0));
10748 default:
10749 STRANGE
10750 }
10751 return(0);
10752}
10753
10754/**
10755 * xmlXPathCompile:
10756 * @str: the XPath expression
10757 *
10758 * Compile an XPath expression
10759 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010760 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010761 * the caller has to free the object.
10762 */
10763xmlXPathCompExprPtr
10764xmlXPathCompile(const xmlChar *str) {
10765 xmlXPathParserContextPtr ctxt;
10766 xmlXPathCompExprPtr comp;
10767
10768 xmlXPathInit();
10769
10770 ctxt = xmlXPathNewParserContext(str, NULL);
10771 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010772
Daniel Veillard40af6492001-04-22 08:50:55 +000010773 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010774 /*
10775 * aleksey: in some cases this line prints *second* error message
10776 * (see bug #78858) and probably this should be fixed.
10777 * However, we are not sure that all error messages are printed
10778 * out in other places. It's not critical so we leave it as-is for now
10779 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010780 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10781 comp = NULL;
10782 } else {
10783 comp = ctxt->comp;
10784 ctxt->comp = NULL;
10785 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010786 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010787 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010788 comp->expr = xmlStrdup(str);
10789#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010790 comp->string = xmlStrdup(str);
10791 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010792#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010793 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010794 return(comp);
10795}
10796
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010797/**
10798 * xmlXPathCompiledEval:
10799 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010800 * @ctx: the XPath context
10801 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010802 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010803 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010804 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010805 * the caller has to free the object.
10806 */
10807xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010808xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010809 xmlXPathParserContextPtr ctxt;
10810 xmlXPathObjectPtr res, tmp, init = NULL;
10811 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010812#ifndef LIBXML_THREAD_ENABLED
10813 static int reentance = 0;
10814#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010815
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010816 if ((comp == NULL) || (ctx == NULL))
10817 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010818 xmlXPathInit();
10819
10820 CHECK_CONTEXT(ctx)
10821
Daniel Veillard81463942001-10-16 12:34:39 +000010822#ifndef LIBXML_THREAD_ENABLED
10823 reentance++;
10824 if (reentance > 1)
10825 xmlXPathDisableOptimizer = 1;
10826#endif
10827
Daniel Veillardf06307e2001-07-03 10:35:50 +000010828#ifdef DEBUG_EVAL_COUNTS
10829 comp->nb++;
10830 if ((comp->string != NULL) && (comp->nb > 100)) {
10831 fprintf(stderr, "100 x %s\n", comp->string);
10832 comp->nb = 0;
10833 }
10834#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010835 ctxt = xmlXPathCompParserContext(comp, ctx);
10836 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010837
10838 if (ctxt->value == NULL) {
10839 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010840 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010841 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010842 } else {
10843 res = valuePop(ctxt);
10844 }
10845
Daniel Veillardf06307e2001-07-03 10:35:50 +000010846
Owen Taylor3473f882001-02-23 17:55:21 +000010847 do {
10848 tmp = valuePop(ctxt);
10849 if (tmp != NULL) {
10850 if (tmp != init)
10851 stack++;
10852 xmlXPathFreeObject(tmp);
10853 }
10854 } while (tmp != NULL);
10855 if ((stack != 0) && (res != NULL)) {
10856 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010857 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010858 stack);
10859 }
10860 if (ctxt->error != XPATH_EXPRESSION_OK) {
10861 xmlXPathFreeObject(res);
10862 res = NULL;
10863 }
10864
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010865
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010866 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010867 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010868#ifndef LIBXML_THREAD_ENABLED
10869 reentance--;
10870#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010871 return(res);
10872}
10873
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010874/**
10875 * xmlXPathEvalExpr:
10876 * @ctxt: the XPath Parser context
10877 *
10878 * Parse and evaluate an XPath expression in the given context,
10879 * then push the result on the context stack
10880 */
10881void
10882xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10883 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010884 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010885 xmlXPathRunEval(ctxt);
10886}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010887
10888/**
10889 * xmlXPathEval:
10890 * @str: the XPath expression
10891 * @ctx: the XPath context
10892 *
10893 * Evaluate the XPath Location Path in the given context.
10894 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010895 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010896 * the caller has to free the object.
10897 */
10898xmlXPathObjectPtr
10899xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10900 xmlXPathParserContextPtr ctxt;
10901 xmlXPathObjectPtr res, tmp, init = NULL;
10902 int stack = 0;
10903
10904 xmlXPathInit();
10905
10906 CHECK_CONTEXT(ctx)
10907
10908 ctxt = xmlXPathNewParserContext(str, ctx);
10909 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010910
10911 if (ctxt->value == NULL) {
10912 xmlGenericError(xmlGenericErrorContext,
10913 "xmlXPathEval: evaluation failed\n");
10914 res = NULL;
10915 } else if (*ctxt->cur != 0) {
10916 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10917 res = NULL;
10918 } else {
10919 res = valuePop(ctxt);
10920 }
10921
10922 do {
10923 tmp = valuePop(ctxt);
10924 if (tmp != NULL) {
10925 if (tmp != init)
10926 stack++;
10927 xmlXPathFreeObject(tmp);
10928 }
10929 } while (tmp != NULL);
10930 if ((stack != 0) && (res != NULL)) {
10931 xmlGenericError(xmlGenericErrorContext,
10932 "xmlXPathEval: %d object left on the stack\n",
10933 stack);
10934 }
10935 if (ctxt->error != XPATH_EXPRESSION_OK) {
10936 xmlXPathFreeObject(res);
10937 res = NULL;
10938 }
10939
Owen Taylor3473f882001-02-23 17:55:21 +000010940 xmlXPathFreeParserContext(ctxt);
10941 return(res);
10942}
10943
10944/**
10945 * xmlXPathEvalExpression:
10946 * @str: the XPath expression
10947 * @ctxt: the XPath context
10948 *
10949 * Evaluate the XPath expression in the given context.
10950 *
10951 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10952 * the caller has to free the object.
10953 */
10954xmlXPathObjectPtr
10955xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10956 xmlXPathParserContextPtr pctxt;
10957 xmlXPathObjectPtr res, tmp;
10958 int stack = 0;
10959
10960 xmlXPathInit();
10961
10962 CHECK_CONTEXT(ctxt)
10963
10964 pctxt = xmlXPathNewParserContext(str, ctxt);
10965 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010966
10967 if (*pctxt->cur != 0) {
10968 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10969 res = NULL;
10970 } else {
10971 res = valuePop(pctxt);
10972 }
10973 do {
10974 tmp = valuePop(pctxt);
10975 if (tmp != NULL) {
10976 xmlXPathFreeObject(tmp);
10977 stack++;
10978 }
10979 } while (tmp != NULL);
10980 if ((stack != 0) && (res != NULL)) {
10981 xmlGenericError(xmlGenericErrorContext,
10982 "xmlXPathEvalExpression: %d object left on the stack\n",
10983 stack);
10984 }
10985 xmlXPathFreeParserContext(pctxt);
10986 return(res);
10987}
10988
Daniel Veillard42766c02002-08-22 20:52:17 +000010989/************************************************************************
10990 * *
10991 * Extra functions not pertaining to the XPath spec *
10992 * *
10993 ************************************************************************/
10994/**
10995 * xmlXPathEscapeUriFunction:
10996 * @ctxt: the XPath Parser context
10997 * @nargs: the number of arguments
10998 *
10999 * Implement the escape-uri() XPath function
11000 * string escape-uri(string $str, bool $escape-reserved)
11001 *
11002 * This function applies the URI escaping rules defined in section 2 of [RFC
11003 * 2396] to the string supplied as $uri-part, which typically represents all
11004 * or part of a URI. The effect of the function is to replace any special
11005 * character in the string by an escape sequence of the form %xx%yy...,
11006 * where xxyy... is the hexadecimal representation of the octets used to
11007 * represent the character in UTF-8.
11008 *
11009 * The set of characters that are escaped depends on the setting of the
11010 * boolean argument $escape-reserved.
11011 *
11012 * If $escape-reserved is true, all characters are escaped other than lower
11013 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11014 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11015 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11016 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11017 * A-F).
11018 *
11019 * If $escape-reserved is false, the behavior differs in that characters
11020 * referred to in [RFC 2396] as reserved characters are not escaped. These
11021 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11022 *
11023 * [RFC 2396] does not define whether escaped URIs should use lower case or
11024 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11025 * compared using string comparison functions, this function must always use
11026 * the upper-case letters A-F.
11027 *
11028 * Generally, $escape-reserved should be set to true when escaping a string
11029 * that is to form a single part of a URI, and to false when escaping an
11030 * entire URI or URI reference.
11031 *
11032 * In the case of non-ascii characters, the string is encoded according to
11033 * utf-8 and then converted according to RFC 2396.
11034 *
11035 * Examples
11036 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11037 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11038 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11039 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11040 *
11041 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011042static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011043xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11044 xmlXPathObjectPtr str;
11045 int escape_reserved;
11046 xmlBufferPtr target;
11047 xmlChar *cptr;
11048 xmlChar escape[4];
11049
11050 CHECK_ARITY(2);
11051
11052 escape_reserved = xmlXPathPopBoolean(ctxt);
11053
11054 CAST_TO_STRING;
11055 str = valuePop(ctxt);
11056
11057 target = xmlBufferCreate();
11058
11059 escape[0] = '%';
11060 escape[3] = 0;
11061
11062 if (target) {
11063 for (cptr = str->stringval; *cptr; cptr++) {
11064 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11065 (*cptr >= 'a' && *cptr <= 'z') ||
11066 (*cptr >= '0' && *cptr <= '9') ||
11067 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11068 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11069 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11070 (*cptr == '%' &&
11071 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11072 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11073 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11074 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11075 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11076 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11077 (!escape_reserved &&
11078 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11079 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11080 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11081 *cptr == ','))) {
11082 xmlBufferAdd(target, cptr, 1);
11083 } else {
11084 if ((*cptr >> 4) < 10)
11085 escape[1] = '0' + (*cptr >> 4);
11086 else
11087 escape[1] = 'A' - 10 + (*cptr >> 4);
11088 if ((*cptr & 0xF) < 10)
11089 escape[2] = '0' + (*cptr & 0xF);
11090 else
11091 escape[2] = 'A' - 10 + (*cptr & 0xF);
11092
11093 xmlBufferAdd(target, &escape[0], 3);
11094 }
11095 }
11096 }
11097 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11098 xmlBufferFree(target);
11099 xmlXPathFreeObject(str);
11100}
11101
Owen Taylor3473f882001-02-23 17:55:21 +000011102/**
11103 * xmlXPathRegisterAllFunctions:
11104 * @ctxt: the XPath context
11105 *
11106 * Registers all default XPath functions in this context
11107 */
11108void
11109xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11110{
11111 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11112 xmlXPathBooleanFunction);
11113 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11114 xmlXPathCeilingFunction);
11115 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11116 xmlXPathCountFunction);
11117 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11118 xmlXPathConcatFunction);
11119 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11120 xmlXPathContainsFunction);
11121 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11122 xmlXPathIdFunction);
11123 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11124 xmlXPathFalseFunction);
11125 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11126 xmlXPathFloorFunction);
11127 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11128 xmlXPathLastFunction);
11129 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11130 xmlXPathLangFunction);
11131 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11132 xmlXPathLocalNameFunction);
11133 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11134 xmlXPathNotFunction);
11135 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11136 xmlXPathNameFunction);
11137 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11138 xmlXPathNamespaceURIFunction);
11139 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11140 xmlXPathNormalizeFunction);
11141 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11142 xmlXPathNumberFunction);
11143 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11144 xmlXPathPositionFunction);
11145 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11146 xmlXPathRoundFunction);
11147 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11148 xmlXPathStringFunction);
11149 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11150 xmlXPathStringLengthFunction);
11151 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11152 xmlXPathStartsWithFunction);
11153 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11154 xmlXPathSubstringFunction);
11155 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11156 xmlXPathSubstringBeforeFunction);
11157 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11158 xmlXPathSubstringAfterFunction);
11159 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11160 xmlXPathSumFunction);
11161 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11162 xmlXPathTrueFunction);
11163 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11164 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011165
11166 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11167 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11168 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011169}
11170
11171#endif /* LIBXML_XPATH_ENABLED */