blob: 605b5887251f4652fe97418b5cfdb3eccbe3a9cf [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);
5761 ctxt->ancestor = cur->parent;
5762 }
5763 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5764 cur = cur->prev;
5765 while (cur->prev == NULL) {
5766 cur = cur->parent;
5767 if (cur == NULL)
5768 return (NULL);
5769 if (cur == ctxt->context->doc->children)
5770 return (NULL);
5771 if (cur != ctxt->ancestor)
5772 return (cur);
5773 ctxt->ancestor = cur->parent;
5774 }
5775 cur = cur->prev;
5776 while (cur->last != NULL)
5777 cur = cur->last;
5778 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005779}
5780
5781/**
5782 * xmlXPathNextNamespace:
5783 * @ctxt: the XPath Parser context
5784 * @cur: the current attribute in the traversal
5785 *
5786 * Traversal function for the "namespace" direction
5787 * the namespace axis contains the namespace nodes of the context node;
5788 * the order of nodes on this axis is implementation-defined; the axis will
5789 * be empty unless the context node is an element
5790 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005791 * We keep the XML namespace node at the end of the list.
5792 *
Owen Taylor3473f882001-02-23 17:55:21 +00005793 * Returns the next element following that axis
5794 */
5795xmlNodePtr
5796xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5797 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005798 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005799 if (ctxt->context->tmpNsList != NULL)
5800 xmlFree(ctxt->context->tmpNsList);
5801 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005802 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005803 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005804 if (ctxt->context->tmpNsList != NULL) {
5805 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5806 ctxt->context->tmpNsNr++;
5807 }
5808 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005809 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005810 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005811 if (ctxt->context->tmpNsNr > 0) {
5812 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5813 } else {
5814 if (ctxt->context->tmpNsList != NULL)
5815 xmlFree(ctxt->context->tmpNsList);
5816 ctxt->context->tmpNsList = NULL;
5817 return(NULL);
5818 }
Owen Taylor3473f882001-02-23 17:55:21 +00005819}
5820
5821/**
5822 * xmlXPathNextAttribute:
5823 * @ctxt: the XPath Parser context
5824 * @cur: the current attribute in the traversal
5825 *
5826 * Traversal function for the "attribute" direction
5827 * TODO: support DTD inherited default attributes
5828 *
5829 * Returns the next element following that axis
5830 */
5831xmlNodePtr
5832xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005833 if (ctxt->context->node == NULL)
5834 return(NULL);
5835 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5836 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005837 if (cur == NULL) {
5838 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5839 return(NULL);
5840 return((xmlNodePtr)ctxt->context->node->properties);
5841 }
5842 return((xmlNodePtr)cur->next);
5843}
5844
5845/************************************************************************
5846 * *
5847 * NodeTest Functions *
5848 * *
5849 ************************************************************************/
5850
Owen Taylor3473f882001-02-23 17:55:21 +00005851#define IS_FUNCTION 200
5852
Owen Taylor3473f882001-02-23 17:55:21 +00005853
5854/************************************************************************
5855 * *
5856 * Implicit tree core function library *
5857 * *
5858 ************************************************************************/
5859
5860/**
5861 * xmlXPathRoot:
5862 * @ctxt: the XPath Parser context
5863 *
5864 * Initialize the context to the root of the document
5865 */
5866void
5867xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5868 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5869 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5870}
5871
5872/************************************************************************
5873 * *
5874 * The explicit core function library *
5875 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5876 * *
5877 ************************************************************************/
5878
5879
5880/**
5881 * xmlXPathLastFunction:
5882 * @ctxt: the XPath Parser context
5883 * @nargs: the number of arguments
5884 *
5885 * Implement the last() XPath function
5886 * number last()
5887 * The last function returns the number of nodes in the context node list.
5888 */
5889void
5890xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5891 CHECK_ARITY(0);
5892 if (ctxt->context->contextSize >= 0) {
5893 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5894#ifdef DEBUG_EXPR
5895 xmlGenericError(xmlGenericErrorContext,
5896 "last() : %d\n", ctxt->context->contextSize);
5897#endif
5898 } else {
5899 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5900 }
5901}
5902
5903/**
5904 * xmlXPathPositionFunction:
5905 * @ctxt: the XPath Parser context
5906 * @nargs: the number of arguments
5907 *
5908 * Implement the position() XPath function
5909 * number position()
5910 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005911 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005912 * will be equal to last().
5913 */
5914void
5915xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5916 CHECK_ARITY(0);
5917 if (ctxt->context->proximityPosition >= 0) {
5918 valuePush(ctxt,
5919 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5920#ifdef DEBUG_EXPR
5921 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5922 ctxt->context->proximityPosition);
5923#endif
5924 } else {
5925 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5926 }
5927}
5928
5929/**
5930 * xmlXPathCountFunction:
5931 * @ctxt: the XPath Parser context
5932 * @nargs: the number of arguments
5933 *
5934 * Implement the count() XPath function
5935 * number count(node-set)
5936 */
5937void
5938xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5939 xmlXPathObjectPtr cur;
5940
5941 CHECK_ARITY(1);
5942 if ((ctxt->value == NULL) ||
5943 ((ctxt->value->type != XPATH_NODESET) &&
5944 (ctxt->value->type != XPATH_XSLT_TREE)))
5945 XP_ERROR(XPATH_INVALID_TYPE);
5946 cur = valuePop(ctxt);
5947
Daniel Veillard911f49a2001-04-07 15:39:35 +00005948 if ((cur == NULL) || (cur->nodesetval == NULL))
5949 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005950 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005951 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005952 } else {
5953 if ((cur->nodesetval->nodeNr != 1) ||
5954 (cur->nodesetval->nodeTab == NULL)) {
5955 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5956 } else {
5957 xmlNodePtr tmp;
5958 int i = 0;
5959
5960 tmp = cur->nodesetval->nodeTab[0];
5961 if (tmp != NULL) {
5962 tmp = tmp->children;
5963 while (tmp != NULL) {
5964 tmp = tmp->next;
5965 i++;
5966 }
5967 }
5968 valuePush(ctxt, xmlXPathNewFloat((double) i));
5969 }
5970 }
Owen Taylor3473f882001-02-23 17:55:21 +00005971 xmlXPathFreeObject(cur);
5972}
5973
5974/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005975 * xmlXPathGetElementsByIds:
5976 * @doc: the document
5977 * @ids: a whitespace separated list of IDs
5978 *
5979 * Selects elements by their unique ID.
5980 *
5981 * Returns a node-set of selected elements.
5982 */
5983static xmlNodeSetPtr
5984xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5985 xmlNodeSetPtr ret;
5986 const xmlChar *cur = ids;
5987 xmlChar *ID;
5988 xmlAttrPtr attr;
5989 xmlNodePtr elem = NULL;
5990
Daniel Veillard7a985a12003-07-06 17:57:42 +00005991 if (ids == NULL) return(NULL);
5992
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005993 ret = xmlXPathNodeSetCreate(NULL);
5994
5995 while (IS_BLANK(*cur)) cur++;
5996 while (*cur != 0) {
Daniel Veillarde209b332003-03-26 21:40:13 +00005997 while ((!IS_BLANK(*cur)) && (*cur != 0))
5998 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005999
6000 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006001 if (ID != NULL) {
6002 if (xmlValidateNCName(ID, 1) == 0) {
6003 attr = xmlGetID(doc, ID);
6004 if (attr != NULL) {
6005 if (attr->type == XML_ATTRIBUTE_NODE)
6006 elem = attr->parent;
6007 else if (attr->type == XML_ELEMENT_NODE)
6008 elem = (xmlNodePtr) attr;
6009 else
6010 elem = NULL;
6011 if (elem != NULL)
6012 xmlXPathNodeSetAdd(ret, elem);
6013 }
6014 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006015 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006016 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006017
6018 while (IS_BLANK(*cur)) cur++;
6019 ids = cur;
6020 }
6021 return(ret);
6022}
6023
6024/**
Owen Taylor3473f882001-02-23 17:55:21 +00006025 * xmlXPathIdFunction:
6026 * @ctxt: the XPath Parser context
6027 * @nargs: the number of arguments
6028 *
6029 * Implement the id() XPath function
6030 * node-set id(object)
6031 * The id function selects elements by their unique ID
6032 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6033 * then the result is the union of the result of applying id to the
6034 * string value of each of the nodes in the argument node-set. When the
6035 * argument to id is of any other type, the argument is converted to a
6036 * string as if by a call to the string function; the string is split
6037 * into a whitespace-separated list of tokens (whitespace is any sequence
6038 * of characters matching the production S); the result is a node-set
6039 * containing the elements in the same document as the context node that
6040 * have a unique ID equal to any of the tokens in the list.
6041 */
6042void
6043xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006044 xmlChar *tokens;
6045 xmlNodeSetPtr ret;
6046 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006047
6048 CHECK_ARITY(1);
6049 obj = valuePop(ctxt);
6050 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006051 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006052 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006053 int i;
6054
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006055 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006056
Daniel Veillard911f49a2001-04-07 15:39:35 +00006057 if (obj->nodesetval != NULL) {
6058 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006059 tokens =
6060 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6061 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6062 ret = xmlXPathNodeSetMerge(ret, ns);
6063 xmlXPathFreeNodeSet(ns);
6064 if (tokens != NULL)
6065 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006066 }
Owen Taylor3473f882001-02-23 17:55:21 +00006067 }
6068
6069 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006070 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006071 return;
6072 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006073 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006074
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006075 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6076 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006077
Owen Taylor3473f882001-02-23 17:55:21 +00006078 xmlXPathFreeObject(obj);
6079 return;
6080}
6081
6082/**
6083 * xmlXPathLocalNameFunction:
6084 * @ctxt: the XPath Parser context
6085 * @nargs: the number of arguments
6086 *
6087 * Implement the local-name() XPath function
6088 * string local-name(node-set?)
6089 * The local-name function returns a string containing the local part
6090 * of the name of the node in the argument node-set that is first in
6091 * document order. If the node-set is empty or the first node has no
6092 * name, an empty string is returned. If the argument is omitted it
6093 * defaults to the context node.
6094 */
6095void
6096xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6097 xmlXPathObjectPtr cur;
6098
6099 if (nargs == 0) {
6100 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6101 nargs = 1;
6102 }
6103
6104 CHECK_ARITY(1);
6105 if ((ctxt->value == NULL) ||
6106 ((ctxt->value->type != XPATH_NODESET) &&
6107 (ctxt->value->type != XPATH_XSLT_TREE)))
6108 XP_ERROR(XPATH_INVALID_TYPE);
6109 cur = valuePop(ctxt);
6110
Daniel Veillard911f49a2001-04-07 15:39:35 +00006111 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006112 valuePush(ctxt, xmlXPathNewCString(""));
6113 } else {
6114 int i = 0; /* Should be first in document order !!!!! */
6115 switch (cur->nodesetval->nodeTab[i]->type) {
6116 case XML_ELEMENT_NODE:
6117 case XML_ATTRIBUTE_NODE:
6118 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006119 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6120 valuePush(ctxt, xmlXPathNewCString(""));
6121 else
6122 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006123 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6124 break;
6125 case XML_NAMESPACE_DECL:
6126 valuePush(ctxt, xmlXPathNewString(
6127 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6128 break;
6129 default:
6130 valuePush(ctxt, xmlXPathNewCString(""));
6131 }
6132 }
6133 xmlXPathFreeObject(cur);
6134}
6135
6136/**
6137 * xmlXPathNamespaceURIFunction:
6138 * @ctxt: the XPath Parser context
6139 * @nargs: the number of arguments
6140 *
6141 * Implement the namespace-uri() XPath function
6142 * string namespace-uri(node-set?)
6143 * The namespace-uri function returns a string containing the
6144 * namespace URI of the expanded name of the node in the argument
6145 * node-set that is first in document order. If the node-set is empty,
6146 * the first node has no name, or the expanded name has no namespace
6147 * URI, an empty string is returned. If the argument is omitted it
6148 * defaults to the context node.
6149 */
6150void
6151xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6152 xmlXPathObjectPtr cur;
6153
6154 if (nargs == 0) {
6155 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6156 nargs = 1;
6157 }
6158 CHECK_ARITY(1);
6159 if ((ctxt->value == NULL) ||
6160 ((ctxt->value->type != XPATH_NODESET) &&
6161 (ctxt->value->type != XPATH_XSLT_TREE)))
6162 XP_ERROR(XPATH_INVALID_TYPE);
6163 cur = valuePop(ctxt);
6164
Daniel Veillard911f49a2001-04-07 15:39:35 +00006165 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006166 valuePush(ctxt, xmlXPathNewCString(""));
6167 } else {
6168 int i = 0; /* Should be first in document order !!!!! */
6169 switch (cur->nodesetval->nodeTab[i]->type) {
6170 case XML_ELEMENT_NODE:
6171 case XML_ATTRIBUTE_NODE:
6172 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6173 valuePush(ctxt, xmlXPathNewCString(""));
6174 else
6175 valuePush(ctxt, xmlXPathNewString(
6176 cur->nodesetval->nodeTab[i]->ns->href));
6177 break;
6178 default:
6179 valuePush(ctxt, xmlXPathNewCString(""));
6180 }
6181 }
6182 xmlXPathFreeObject(cur);
6183}
6184
6185/**
6186 * xmlXPathNameFunction:
6187 * @ctxt: the XPath Parser context
6188 * @nargs: the number of arguments
6189 *
6190 * Implement the name() XPath function
6191 * string name(node-set?)
6192 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006193 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006194 * order. The QName must represent the name with respect to the namespace
6195 * declarations in effect on the node whose name is being represented.
6196 * Typically, this will be the form in which the name occurred in the XML
6197 * source. This need not be the case if there are namespace declarations
6198 * in effect on the node that associate multiple prefixes with the same
6199 * namespace. However, an implementation may include information about
6200 * the original prefix in its representation of nodes; in this case, an
6201 * implementation can ensure that the returned string is always the same
6202 * as the QName used in the XML source. If the argument it omitted it
6203 * defaults to the context node.
6204 * Libxml keep the original prefix so the "real qualified name" used is
6205 * returned.
6206 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006207static void
Daniel Veillard04383752001-07-08 14:27:15 +00006208xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6209{
Owen Taylor3473f882001-02-23 17:55:21 +00006210 xmlXPathObjectPtr cur;
6211
6212 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006213 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6214 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006215 }
6216
6217 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006218 if ((ctxt->value == NULL) ||
6219 ((ctxt->value->type != XPATH_NODESET) &&
6220 (ctxt->value->type != XPATH_XSLT_TREE)))
6221 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006222 cur = valuePop(ctxt);
6223
Daniel Veillard911f49a2001-04-07 15:39:35 +00006224 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006225 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006226 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006227 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006228
Daniel Veillard04383752001-07-08 14:27:15 +00006229 switch (cur->nodesetval->nodeTab[i]->type) {
6230 case XML_ELEMENT_NODE:
6231 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006232 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6233 valuePush(ctxt, xmlXPathNewCString(""));
6234 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6235 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006236 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006237 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006238
Daniel Veillard652d8a92003-02-04 19:28:49 +00006239 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006240 xmlChar *fullname;
6241
6242 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6243 cur->nodesetval->nodeTab[i]->ns->prefix,
6244 NULL, 0);
6245 if (fullname == cur->nodesetval->nodeTab[i]->name)
6246 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6247 if (fullname == NULL) {
6248 XP_ERROR(XPATH_MEMORY_ERROR);
6249 }
6250 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006251 }
6252 break;
6253 default:
6254 valuePush(ctxt,
6255 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6256 xmlXPathLocalNameFunction(ctxt, 1);
6257 }
Owen Taylor3473f882001-02-23 17:55:21 +00006258 }
6259 xmlXPathFreeObject(cur);
6260}
6261
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006262
6263/**
Owen Taylor3473f882001-02-23 17:55:21 +00006264 * xmlXPathStringFunction:
6265 * @ctxt: the XPath Parser context
6266 * @nargs: the number of arguments
6267 *
6268 * Implement the string() XPath function
6269 * string string(object?)
6270 * he string function converts an object to a string as follows:
6271 * - A node-set is converted to a string by returning the value of
6272 * the node in the node-set that is first in document order.
6273 * If the node-set is empty, an empty string is returned.
6274 * - A number is converted to a string as follows
6275 * + NaN is converted to the string NaN
6276 * + positive zero is converted to the string 0
6277 * + negative zero is converted to the string 0
6278 * + positive infinity is converted to the string Infinity
6279 * + negative infinity is converted to the string -Infinity
6280 * + if the number is an integer, the number is represented in
6281 * decimal form as a Number with no decimal point and no leading
6282 * zeros, preceded by a minus sign (-) if the number is negative
6283 * + otherwise, the number is represented in decimal form as a
6284 * Number including a decimal point with at least one digit
6285 * before the decimal point and at least one digit after the
6286 * decimal point, preceded by a minus sign (-) if the number
6287 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006288 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006289 * before the decimal point; beyond the one required digit
6290 * after the decimal point there must be as many, but only as
6291 * many, more digits as are needed to uniquely distinguish the
6292 * number from all other IEEE 754 numeric values.
6293 * - The boolean false value is converted to the string false.
6294 * The boolean true value is converted to the string true.
6295 *
6296 * If the argument is omitted, it defaults to a node-set with the
6297 * context node as its only member.
6298 */
6299void
6300xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6301 xmlXPathObjectPtr cur;
6302
6303 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006304 valuePush(ctxt,
6305 xmlXPathWrapString(
6306 xmlXPathCastNodeToString(ctxt->context->node)));
6307 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006308 }
6309
6310 CHECK_ARITY(1);
6311 cur = valuePop(ctxt);
6312 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006313 cur = xmlXPathConvertString(cur);
6314 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006315}
6316
6317/**
6318 * xmlXPathStringLengthFunction:
6319 * @ctxt: the XPath Parser context
6320 * @nargs: the number of arguments
6321 *
6322 * Implement the string-length() XPath function
6323 * number string-length(string?)
6324 * The string-length returns the number of characters in the string
6325 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6326 * the context node converted to a string, in other words the value
6327 * of the context node.
6328 */
6329void
6330xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6331 xmlXPathObjectPtr cur;
6332
6333 if (nargs == 0) {
6334 if (ctxt->context->node == NULL) {
6335 valuePush(ctxt, xmlXPathNewFloat(0));
6336 } else {
6337 xmlChar *content;
6338
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006339 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006340 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006341 xmlFree(content);
6342 }
6343 return;
6344 }
6345 CHECK_ARITY(1);
6346 CAST_TO_STRING;
6347 CHECK_TYPE(XPATH_STRING);
6348 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006349 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006350 xmlXPathFreeObject(cur);
6351}
6352
6353/**
6354 * xmlXPathConcatFunction:
6355 * @ctxt: the XPath Parser context
6356 * @nargs: the number of arguments
6357 *
6358 * Implement the concat() XPath function
6359 * string concat(string, string, string*)
6360 * The concat function returns the concatenation of its arguments.
6361 */
6362void
6363xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6364 xmlXPathObjectPtr cur, newobj;
6365 xmlChar *tmp;
6366
6367 if (nargs < 2) {
6368 CHECK_ARITY(2);
6369 }
6370
6371 CAST_TO_STRING;
6372 cur = valuePop(ctxt);
6373 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6374 xmlXPathFreeObject(cur);
6375 return;
6376 }
6377 nargs--;
6378
6379 while (nargs > 0) {
6380 CAST_TO_STRING;
6381 newobj = valuePop(ctxt);
6382 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6383 xmlXPathFreeObject(newobj);
6384 xmlXPathFreeObject(cur);
6385 XP_ERROR(XPATH_INVALID_TYPE);
6386 }
6387 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6388 newobj->stringval = cur->stringval;
6389 cur->stringval = tmp;
6390
6391 xmlXPathFreeObject(newobj);
6392 nargs--;
6393 }
6394 valuePush(ctxt, cur);
6395}
6396
6397/**
6398 * xmlXPathContainsFunction:
6399 * @ctxt: the XPath Parser context
6400 * @nargs: the number of arguments
6401 *
6402 * Implement the contains() XPath function
6403 * boolean contains(string, string)
6404 * The contains function returns true if the first argument string
6405 * contains the second argument string, and otherwise returns false.
6406 */
6407void
6408xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6409 xmlXPathObjectPtr hay, needle;
6410
6411 CHECK_ARITY(2);
6412 CAST_TO_STRING;
6413 CHECK_TYPE(XPATH_STRING);
6414 needle = valuePop(ctxt);
6415 CAST_TO_STRING;
6416 hay = valuePop(ctxt);
6417 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6418 xmlXPathFreeObject(hay);
6419 xmlXPathFreeObject(needle);
6420 XP_ERROR(XPATH_INVALID_TYPE);
6421 }
6422 if (xmlStrstr(hay->stringval, needle->stringval))
6423 valuePush(ctxt, xmlXPathNewBoolean(1));
6424 else
6425 valuePush(ctxt, xmlXPathNewBoolean(0));
6426 xmlXPathFreeObject(hay);
6427 xmlXPathFreeObject(needle);
6428}
6429
6430/**
6431 * xmlXPathStartsWithFunction:
6432 * @ctxt: the XPath Parser context
6433 * @nargs: the number of arguments
6434 *
6435 * Implement the starts-with() XPath function
6436 * boolean starts-with(string, string)
6437 * The starts-with function returns true if the first argument string
6438 * starts with the second argument string, and otherwise returns false.
6439 */
6440void
6441xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6442 xmlXPathObjectPtr hay, needle;
6443 int n;
6444
6445 CHECK_ARITY(2);
6446 CAST_TO_STRING;
6447 CHECK_TYPE(XPATH_STRING);
6448 needle = valuePop(ctxt);
6449 CAST_TO_STRING;
6450 hay = valuePop(ctxt);
6451 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6452 xmlXPathFreeObject(hay);
6453 xmlXPathFreeObject(needle);
6454 XP_ERROR(XPATH_INVALID_TYPE);
6455 }
6456 n = xmlStrlen(needle->stringval);
6457 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6458 valuePush(ctxt, xmlXPathNewBoolean(0));
6459 else
6460 valuePush(ctxt, xmlXPathNewBoolean(1));
6461 xmlXPathFreeObject(hay);
6462 xmlXPathFreeObject(needle);
6463}
6464
6465/**
6466 * xmlXPathSubstringFunction:
6467 * @ctxt: the XPath Parser context
6468 * @nargs: the number of arguments
6469 *
6470 * Implement the substring() XPath function
6471 * string substring(string, number, number?)
6472 * The substring function returns the substring of the first argument
6473 * starting at the position specified in the second argument with
6474 * length specified in the third argument. For example,
6475 * substring("12345",2,3) returns "234". If the third argument is not
6476 * specified, it returns the substring starting at the position specified
6477 * in the second argument and continuing to the end of the string. For
6478 * example, substring("12345",2) returns "2345". More precisely, each
6479 * character in the string (see [3.6 Strings]) is considered to have a
6480 * numeric position: the position of the first character is 1, the position
6481 * of the second character is 2 and so on. The returned substring contains
6482 * those characters for which the position of the character is greater than
6483 * or equal to the second argument and, if the third argument is specified,
6484 * less than the sum of the second and third arguments; the comparisons
6485 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6486 * - substring("12345", 1.5, 2.6) returns "234"
6487 * - substring("12345", 0, 3) returns "12"
6488 * - substring("12345", 0 div 0, 3) returns ""
6489 * - substring("12345", 1, 0 div 0) returns ""
6490 * - substring("12345", -42, 1 div 0) returns "12345"
6491 * - substring("12345", -1 div 0, 1 div 0) returns ""
6492 */
6493void
6494xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6495 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006496 double le=0, in;
6497 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006498 xmlChar *ret;
6499
Owen Taylor3473f882001-02-23 17:55:21 +00006500 if (nargs < 2) {
6501 CHECK_ARITY(2);
6502 }
6503 if (nargs > 3) {
6504 CHECK_ARITY(3);
6505 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006506 /*
6507 * take care of possible last (position) argument
6508 */
Owen Taylor3473f882001-02-23 17:55:21 +00006509 if (nargs == 3) {
6510 CAST_TO_NUMBER;
6511 CHECK_TYPE(XPATH_NUMBER);
6512 len = valuePop(ctxt);
6513 le = len->floatval;
6514 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006515 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006516
Owen Taylor3473f882001-02-23 17:55:21 +00006517 CAST_TO_NUMBER;
6518 CHECK_TYPE(XPATH_NUMBER);
6519 start = valuePop(ctxt);
6520 in = start->floatval;
6521 xmlXPathFreeObject(start);
6522 CAST_TO_STRING;
6523 CHECK_TYPE(XPATH_STRING);
6524 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006525 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006526
Daniel Veillard97ac1312001-05-30 19:14:17 +00006527 /*
6528 * If last pos not present, calculate last position
6529 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006530 if (nargs != 3) {
6531 le = (double)m;
6532 if (in < 1.0)
6533 in = 1.0;
6534 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006535
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006536 /* Need to check for the special cases where either
6537 * the index is NaN, the length is NaN, or both
6538 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006539 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006540 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006541 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006542 * To meet the requirements of the spec, the arguments
6543 * must be converted to integer format before
6544 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006545 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006546 * First we go to integer form, rounding up
6547 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006548 */
6549 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006550 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006551
Daniel Veillard9e412302002-06-10 15:59:44 +00006552 if (xmlXPathIsInf(le) == 1) {
6553 l = m;
6554 if (i < 1)
6555 i = 1;
6556 }
6557 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6558 l = 0;
6559 else {
6560 l = (int) le;
6561 if (((double)l)+0.5 <= le) l++;
6562 }
6563
6564 /* Now we normalize inidices */
6565 i -= 1;
6566 l += i;
6567 if (i < 0)
6568 i = 0;
6569 if (l > m)
6570 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006571
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006572 /* number of chars to copy */
6573 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006574
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006575 ret = xmlUTF8Strsub(str->stringval, i, l);
6576 }
6577 else {
6578 ret = NULL;
6579 }
6580
Owen Taylor3473f882001-02-23 17:55:21 +00006581 if (ret == NULL)
6582 valuePush(ctxt, xmlXPathNewCString(""));
6583 else {
6584 valuePush(ctxt, xmlXPathNewString(ret));
6585 xmlFree(ret);
6586 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006587
Owen Taylor3473f882001-02-23 17:55:21 +00006588 xmlXPathFreeObject(str);
6589}
6590
6591/**
6592 * xmlXPathSubstringBeforeFunction:
6593 * @ctxt: the XPath Parser context
6594 * @nargs: the number of arguments
6595 *
6596 * Implement the substring-before() XPath function
6597 * string substring-before(string, string)
6598 * The substring-before function returns the substring of the first
6599 * argument string that precedes the first occurrence of the second
6600 * argument string in the first argument string, or the empty string
6601 * if the first argument string does not contain the second argument
6602 * string. For example, substring-before("1999/04/01","/") returns 1999.
6603 */
6604void
6605xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6606 xmlXPathObjectPtr str;
6607 xmlXPathObjectPtr find;
6608 xmlBufferPtr target;
6609 const xmlChar *point;
6610 int offset;
6611
6612 CHECK_ARITY(2);
6613 CAST_TO_STRING;
6614 find = valuePop(ctxt);
6615 CAST_TO_STRING;
6616 str = valuePop(ctxt);
6617
6618 target = xmlBufferCreate();
6619 if (target) {
6620 point = xmlStrstr(str->stringval, find->stringval);
6621 if (point) {
6622 offset = (int)(point - str->stringval);
6623 xmlBufferAdd(target, str->stringval, offset);
6624 }
6625 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6626 xmlBufferFree(target);
6627 }
6628
6629 xmlXPathFreeObject(str);
6630 xmlXPathFreeObject(find);
6631}
6632
6633/**
6634 * xmlXPathSubstringAfterFunction:
6635 * @ctxt: the XPath Parser context
6636 * @nargs: the number of arguments
6637 *
6638 * Implement the substring-after() XPath function
6639 * string substring-after(string, string)
6640 * The substring-after function returns the substring of the first
6641 * argument string that follows the first occurrence of the second
6642 * argument string in the first argument string, or the empty stringi
6643 * if the first argument string does not contain the second argument
6644 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6645 * and substring-after("1999/04/01","19") returns 99/04/01.
6646 */
6647void
6648xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6649 xmlXPathObjectPtr str;
6650 xmlXPathObjectPtr find;
6651 xmlBufferPtr target;
6652 const xmlChar *point;
6653 int offset;
6654
6655 CHECK_ARITY(2);
6656 CAST_TO_STRING;
6657 find = valuePop(ctxt);
6658 CAST_TO_STRING;
6659 str = valuePop(ctxt);
6660
6661 target = xmlBufferCreate();
6662 if (target) {
6663 point = xmlStrstr(str->stringval, find->stringval);
6664 if (point) {
6665 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6666 xmlBufferAdd(target, &str->stringval[offset],
6667 xmlStrlen(str->stringval) - offset);
6668 }
6669 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6670 xmlBufferFree(target);
6671 }
6672
6673 xmlXPathFreeObject(str);
6674 xmlXPathFreeObject(find);
6675}
6676
6677/**
6678 * xmlXPathNormalizeFunction:
6679 * @ctxt: the XPath Parser context
6680 * @nargs: the number of arguments
6681 *
6682 * Implement the normalize-space() XPath function
6683 * string normalize-space(string?)
6684 * The normalize-space function returns the argument string with white
6685 * space normalized by stripping leading and trailing whitespace
6686 * and replacing sequences of whitespace characters by a single
6687 * space. Whitespace characters are the same allowed by the S production
6688 * in XML. If the argument is omitted, it defaults to the context
6689 * node converted to a string, in other words the value of the context node.
6690 */
6691void
6692xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6693 xmlXPathObjectPtr obj = NULL;
6694 xmlChar *source = NULL;
6695 xmlBufferPtr target;
6696 xmlChar blank;
6697
6698 if (nargs == 0) {
6699 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006700 valuePush(ctxt,
6701 xmlXPathWrapString(
6702 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006703 nargs = 1;
6704 }
6705
6706 CHECK_ARITY(1);
6707 CAST_TO_STRING;
6708 CHECK_TYPE(XPATH_STRING);
6709 obj = valuePop(ctxt);
6710 source = obj->stringval;
6711
6712 target = xmlBufferCreate();
6713 if (target && source) {
6714
6715 /* Skip leading whitespaces */
6716 while (IS_BLANK(*source))
6717 source++;
6718
6719 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6720 blank = 0;
6721 while (*source) {
6722 if (IS_BLANK(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006723 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006724 } else {
6725 if (blank) {
6726 xmlBufferAdd(target, &blank, 1);
6727 blank = 0;
6728 }
6729 xmlBufferAdd(target, source, 1);
6730 }
6731 source++;
6732 }
6733
6734 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6735 xmlBufferFree(target);
6736 }
6737 xmlXPathFreeObject(obj);
6738}
6739
6740/**
6741 * xmlXPathTranslateFunction:
6742 * @ctxt: the XPath Parser context
6743 * @nargs: the number of arguments
6744 *
6745 * Implement the translate() XPath function
6746 * string translate(string, string, string)
6747 * The translate function returns the first argument string with
6748 * occurrences of characters in the second argument string replaced
6749 * by the character at the corresponding position in the third argument
6750 * string. For example, translate("bar","abc","ABC") returns the string
6751 * BAr. If there is a character in the second argument string with no
6752 * character at a corresponding position in the third argument string
6753 * (because the second argument string is longer than the third argument
6754 * string), then occurrences of that character in the first argument
6755 * string are removed. For example, translate("--aaa--","abc-","ABC")
6756 * returns "AAA". If a character occurs more than once in second
6757 * argument string, then the first occurrence determines the replacement
6758 * character. If the third argument string is longer than the second
6759 * argument string, then excess characters are ignored.
6760 */
6761void
6762xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006763 xmlXPathObjectPtr str;
6764 xmlXPathObjectPtr from;
6765 xmlXPathObjectPtr to;
6766 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006767 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006768 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006769 xmlChar *point;
6770 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006771
Daniel Veillarde043ee12001-04-16 14:08:07 +00006772 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006773
Daniel Veillarde043ee12001-04-16 14:08:07 +00006774 CAST_TO_STRING;
6775 to = valuePop(ctxt);
6776 CAST_TO_STRING;
6777 from = valuePop(ctxt);
6778 CAST_TO_STRING;
6779 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006780
Daniel Veillarde043ee12001-04-16 14:08:07 +00006781 target = xmlBufferCreate();
6782 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006783 max = xmlUTF8Strlen(to->stringval);
6784 for (cptr = str->stringval; (ch=*cptr); ) {
6785 offset = xmlUTF8Strloc(from->stringval, cptr);
6786 if (offset >= 0) {
6787 if (offset < max) {
6788 point = xmlUTF8Strpos(to->stringval, offset);
6789 if (point)
6790 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6791 }
6792 } else
6793 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6794
6795 /* Step to next character in input */
6796 cptr++;
6797 if ( ch & 0x80 ) {
6798 /* if not simple ascii, verify proper format */
6799 if ( (ch & 0xc0) != 0xc0 ) {
6800 xmlGenericError(xmlGenericErrorContext,
6801 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6802 break;
6803 }
6804 /* then skip over remaining bytes for this char */
6805 while ( (ch <<= 1) & 0x80 )
6806 if ( (*cptr++ & 0xc0) != 0x80 ) {
6807 xmlGenericError(xmlGenericErrorContext,
6808 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6809 break;
6810 }
6811 if (ch & 0x80) /* must have had error encountered */
6812 break;
6813 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006814 }
Owen Taylor3473f882001-02-23 17:55:21 +00006815 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006816 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6817 xmlBufferFree(target);
6818 xmlXPathFreeObject(str);
6819 xmlXPathFreeObject(from);
6820 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006821}
6822
6823/**
6824 * xmlXPathBooleanFunction:
6825 * @ctxt: the XPath Parser context
6826 * @nargs: the number of arguments
6827 *
6828 * Implement the boolean() XPath function
6829 * boolean boolean(object)
6830 * he boolean function converts its argument to a boolean as follows:
6831 * - a number is true if and only if it is neither positive or
6832 * negative zero nor NaN
6833 * - a node-set is true if and only if it is non-empty
6834 * - a string is true if and only if its length is non-zero
6835 */
6836void
6837xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6838 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006839
6840 CHECK_ARITY(1);
6841 cur = valuePop(ctxt);
6842 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006843 cur = xmlXPathConvertBoolean(cur);
6844 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006845}
6846
6847/**
6848 * xmlXPathNotFunction:
6849 * @ctxt: the XPath Parser context
6850 * @nargs: the number of arguments
6851 *
6852 * Implement the not() XPath function
6853 * boolean not(boolean)
6854 * The not function returns true if its argument is false,
6855 * and false otherwise.
6856 */
6857void
6858xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6859 CHECK_ARITY(1);
6860 CAST_TO_BOOLEAN;
6861 CHECK_TYPE(XPATH_BOOLEAN);
6862 ctxt->value->boolval = ! ctxt->value->boolval;
6863}
6864
6865/**
6866 * xmlXPathTrueFunction:
6867 * @ctxt: the XPath Parser context
6868 * @nargs: the number of arguments
6869 *
6870 * Implement the true() XPath function
6871 * boolean true()
6872 */
6873void
6874xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6875 CHECK_ARITY(0);
6876 valuePush(ctxt, xmlXPathNewBoolean(1));
6877}
6878
6879/**
6880 * xmlXPathFalseFunction:
6881 * @ctxt: the XPath Parser context
6882 * @nargs: the number of arguments
6883 *
6884 * Implement the false() XPath function
6885 * boolean false()
6886 */
6887void
6888xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6889 CHECK_ARITY(0);
6890 valuePush(ctxt, xmlXPathNewBoolean(0));
6891}
6892
6893/**
6894 * xmlXPathLangFunction:
6895 * @ctxt: the XPath Parser context
6896 * @nargs: the number of arguments
6897 *
6898 * Implement the lang() XPath function
6899 * boolean lang(string)
6900 * The lang function returns true or false depending on whether the
6901 * language of the context node as specified by xml:lang attributes
6902 * is the same as or is a sublanguage of the language specified by
6903 * the argument string. The language of the context node is determined
6904 * by the value of the xml:lang attribute on the context node, or, if
6905 * the context node has no xml:lang attribute, by the value of the
6906 * xml:lang attribute on the nearest ancestor of the context node that
6907 * has an xml:lang attribute. If there is no such attribute, then lang
6908 * returns false. If there is such an attribute, then lang returns
6909 * true if the attribute value is equal to the argument ignoring case,
6910 * or if there is some suffix starting with - such that the attribute
6911 * value is equal to the argument ignoring that suffix of the attribute
6912 * value and ignoring case.
6913 */
6914void
6915xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6916 xmlXPathObjectPtr val;
6917 const xmlChar *theLang;
6918 const xmlChar *lang;
6919 int ret = 0;
6920 int i;
6921
6922 CHECK_ARITY(1);
6923 CAST_TO_STRING;
6924 CHECK_TYPE(XPATH_STRING);
6925 val = valuePop(ctxt);
6926 lang = val->stringval;
6927 theLang = xmlNodeGetLang(ctxt->context->node);
6928 if ((theLang != NULL) && (lang != NULL)) {
6929 for (i = 0;lang[i] != 0;i++)
6930 if (toupper(lang[i]) != toupper(theLang[i]))
6931 goto not_equal;
6932 ret = 1;
6933 }
6934not_equal:
6935 xmlXPathFreeObject(val);
6936 valuePush(ctxt, xmlXPathNewBoolean(ret));
6937}
6938
6939/**
6940 * xmlXPathNumberFunction:
6941 * @ctxt: the XPath Parser context
6942 * @nargs: the number of arguments
6943 *
6944 * Implement the number() XPath function
6945 * number number(object?)
6946 */
6947void
6948xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6949 xmlXPathObjectPtr cur;
6950 double res;
6951
6952 if (nargs == 0) {
6953 if (ctxt->context->node == NULL) {
6954 valuePush(ctxt, xmlXPathNewFloat(0.0));
6955 } else {
6956 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6957
6958 res = xmlXPathStringEvalNumber(content);
6959 valuePush(ctxt, xmlXPathNewFloat(res));
6960 xmlFree(content);
6961 }
6962 return;
6963 }
6964
6965 CHECK_ARITY(1);
6966 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006967 cur = xmlXPathConvertNumber(cur);
6968 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006969}
6970
6971/**
6972 * xmlXPathSumFunction:
6973 * @ctxt: the XPath Parser context
6974 * @nargs: the number of arguments
6975 *
6976 * Implement the sum() XPath function
6977 * number sum(node-set)
6978 * The sum function returns the sum of the values of the nodes in
6979 * the argument node-set.
6980 */
6981void
6982xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6983 xmlXPathObjectPtr cur;
6984 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006985 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00006986
6987 CHECK_ARITY(1);
6988 if ((ctxt->value == NULL) ||
6989 ((ctxt->value->type != XPATH_NODESET) &&
6990 (ctxt->value->type != XPATH_XSLT_TREE)))
6991 XP_ERROR(XPATH_INVALID_TYPE);
6992 cur = valuePop(ctxt);
6993
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006994 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006995 valuePush(ctxt, xmlXPathNewFloat(0.0));
6996 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006997 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6998 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006999 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007000 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007001 }
7002 xmlXPathFreeObject(cur);
7003}
7004
7005/**
7006 * xmlXPathFloorFunction:
7007 * @ctxt: the XPath Parser context
7008 * @nargs: the number of arguments
7009 *
7010 * Implement the floor() XPath function
7011 * number floor(number)
7012 * The floor function returns the largest (closest to positive infinity)
7013 * number that is not greater than the argument and that is an integer.
7014 */
7015void
7016xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007017 double f;
7018
Owen Taylor3473f882001-02-23 17:55:21 +00007019 CHECK_ARITY(1);
7020 CAST_TO_NUMBER;
7021 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007022
7023 f = (double)((int) ctxt->value->floatval);
7024 if (f != ctxt->value->floatval) {
7025 if (ctxt->value->floatval > 0)
7026 ctxt->value->floatval = f;
7027 else
7028 ctxt->value->floatval = f - 1;
7029 }
Owen Taylor3473f882001-02-23 17:55:21 +00007030}
7031
7032/**
7033 * xmlXPathCeilingFunction:
7034 * @ctxt: the XPath Parser context
7035 * @nargs: the number of arguments
7036 *
7037 * Implement the ceiling() XPath function
7038 * number ceiling(number)
7039 * The ceiling function returns the smallest (closest to negative infinity)
7040 * number that is not less than the argument and that is an integer.
7041 */
7042void
7043xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7044 double f;
7045
7046 CHECK_ARITY(1);
7047 CAST_TO_NUMBER;
7048 CHECK_TYPE(XPATH_NUMBER);
7049
7050#if 0
7051 ctxt->value->floatval = ceil(ctxt->value->floatval);
7052#else
7053 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007054 if (f != ctxt->value->floatval) {
7055 if (ctxt->value->floatval > 0)
7056 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007057 else {
7058 if (ctxt->value->floatval < 0 && f == 0)
7059 ctxt->value->floatval = xmlXPathNZERO;
7060 else
7061 ctxt->value->floatval = f;
7062 }
7063
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007064 }
Owen Taylor3473f882001-02-23 17:55:21 +00007065#endif
7066}
7067
7068/**
7069 * xmlXPathRoundFunction:
7070 * @ctxt: the XPath Parser context
7071 * @nargs: the number of arguments
7072 *
7073 * Implement the round() XPath function
7074 * number round(number)
7075 * The round function returns the number that is closest to the
7076 * argument and that is an integer. If there are two such numbers,
7077 * then the one that is even is returned.
7078 */
7079void
7080xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7081 double f;
7082
7083 CHECK_ARITY(1);
7084 CAST_TO_NUMBER;
7085 CHECK_TYPE(XPATH_NUMBER);
7086
Daniel Veillardcda96922001-08-21 10:56:31 +00007087 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7088 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7089 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007090 (ctxt->value->floatval == 0.0))
7091 return;
7092
Owen Taylor3473f882001-02-23 17:55:21 +00007093 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007094 if (ctxt->value->floatval < 0) {
7095 if (ctxt->value->floatval < f - 0.5)
7096 ctxt->value->floatval = f - 1;
7097 else
7098 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007099 if (ctxt->value->floatval == 0)
7100 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007101 } else {
7102 if (ctxt->value->floatval < f + 0.5)
7103 ctxt->value->floatval = f;
7104 else
7105 ctxt->value->floatval = f + 1;
7106 }
Owen Taylor3473f882001-02-23 17:55:21 +00007107}
7108
7109/************************************************************************
7110 * *
7111 * The Parser *
7112 * *
7113 ************************************************************************/
7114
7115/*
7116 * a couple of forward declarations since we use a recursive call based
7117 * implementation.
7118 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007119static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007120static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007121static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007122static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007123static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7124 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007125
7126/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007127 * xmlXPathCurrentChar:
7128 * @ctxt: the XPath parser context
7129 * @cur: pointer to the beginning of the char
7130 * @len: pointer to the length of the char read
7131 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007132 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007133 * bytes in the input buffer.
7134 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007135 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007136 */
7137
7138static int
7139xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7140 unsigned char c;
7141 unsigned int val;
7142 const xmlChar *cur;
7143
7144 if (ctxt == NULL)
7145 return(0);
7146 cur = ctxt->cur;
7147
7148 /*
7149 * We are supposed to handle UTF8, check it's valid
7150 * From rfc2044: encoding of the Unicode values on UTF-8:
7151 *
7152 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7153 * 0000 0000-0000 007F 0xxxxxxx
7154 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7155 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7156 *
7157 * Check for the 0x110000 limit too
7158 */
7159 c = *cur;
7160 if (c & 0x80) {
7161 if ((cur[1] & 0xc0) != 0x80)
7162 goto encoding_error;
7163 if ((c & 0xe0) == 0xe0) {
7164
7165 if ((cur[2] & 0xc0) != 0x80)
7166 goto encoding_error;
7167 if ((c & 0xf0) == 0xf0) {
7168 if (((c & 0xf8) != 0xf0) ||
7169 ((cur[3] & 0xc0) != 0x80))
7170 goto encoding_error;
7171 /* 4-byte code */
7172 *len = 4;
7173 val = (cur[0] & 0x7) << 18;
7174 val |= (cur[1] & 0x3f) << 12;
7175 val |= (cur[2] & 0x3f) << 6;
7176 val |= cur[3] & 0x3f;
7177 } else {
7178 /* 3-byte code */
7179 *len = 3;
7180 val = (cur[0] & 0xf) << 12;
7181 val |= (cur[1] & 0x3f) << 6;
7182 val |= cur[2] & 0x3f;
7183 }
7184 } else {
7185 /* 2-byte code */
7186 *len = 2;
7187 val = (cur[0] & 0x1f) << 6;
7188 val |= cur[1] & 0x3f;
7189 }
7190 if (!IS_CHAR(val)) {
7191 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7192 }
7193 return(val);
7194 } else {
7195 /* 1-byte code */
7196 *len = 1;
7197 return((int) *cur);
7198 }
7199encoding_error:
7200 /*
7201 * If we detect an UTF8 error that probably mean that the
7202 * input encoding didn't get properly advertized in the
7203 * declaration header. Report the error and switch the encoding
7204 * to ISO-Latin-1 (if you don't like this policy, just declare the
7205 * encoding !)
7206 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007207 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007208 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007209}
7210
7211/**
Owen Taylor3473f882001-02-23 17:55:21 +00007212 * xmlXPathParseNCName:
7213 * @ctxt: the XPath Parser context
7214 *
7215 * parse an XML namespace non qualified name.
7216 *
7217 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7218 *
7219 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7220 * CombiningChar | Extender
7221 *
7222 * Returns the namespace name or NULL
7223 */
7224
7225xmlChar *
7226xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007227 const xmlChar *in;
7228 xmlChar *ret;
7229 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007230
Daniel Veillard2156a562001-04-28 12:24:34 +00007231 /*
7232 * Accelerator for simple ASCII names
7233 */
7234 in = ctxt->cur;
7235 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7236 ((*in >= 0x41) && (*in <= 0x5A)) ||
7237 (*in == '_')) {
7238 in++;
7239 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7240 ((*in >= 0x41) && (*in <= 0x5A)) ||
7241 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007242 (*in == '_') || (*in == '.') ||
7243 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007244 in++;
7245 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7246 (*in == '[') || (*in == ']') || (*in == ':') ||
7247 (*in == '@') || (*in == '*')) {
7248 count = in - ctxt->cur;
7249 if (count == 0)
7250 return(NULL);
7251 ret = xmlStrndup(ctxt->cur, count);
7252 ctxt->cur = in;
7253 return(ret);
7254 }
7255 }
7256 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007257}
7258
Daniel Veillard2156a562001-04-28 12:24:34 +00007259
Owen Taylor3473f882001-02-23 17:55:21 +00007260/**
7261 * xmlXPathParseQName:
7262 * @ctxt: the XPath Parser context
7263 * @prefix: a xmlChar **
7264 *
7265 * parse an XML qualified name
7266 *
7267 * [NS 5] QName ::= (Prefix ':')? LocalPart
7268 *
7269 * [NS 6] Prefix ::= NCName
7270 *
7271 * [NS 7] LocalPart ::= NCName
7272 *
7273 * Returns the function returns the local part, and prefix is updated
7274 * to get the Prefix if any.
7275 */
7276
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007277static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007278xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7279 xmlChar *ret = NULL;
7280
7281 *prefix = NULL;
7282 ret = xmlXPathParseNCName(ctxt);
7283 if (CUR == ':') {
7284 *prefix = ret;
7285 NEXT;
7286 ret = xmlXPathParseNCName(ctxt);
7287 }
7288 return(ret);
7289}
7290
7291/**
7292 * xmlXPathParseName:
7293 * @ctxt: the XPath Parser context
7294 *
7295 * parse an XML name
7296 *
7297 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7298 * CombiningChar | Extender
7299 *
7300 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7301 *
7302 * Returns the namespace name or NULL
7303 */
7304
7305xmlChar *
7306xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007307 const xmlChar *in;
7308 xmlChar *ret;
7309 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007310
Daniel Veillard61d80a22001-04-27 17:13:01 +00007311 /*
7312 * Accelerator for simple ASCII names
7313 */
7314 in = ctxt->cur;
7315 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7316 ((*in >= 0x41) && (*in <= 0x5A)) ||
7317 (*in == '_') || (*in == ':')) {
7318 in++;
7319 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7320 ((*in >= 0x41) && (*in <= 0x5A)) ||
7321 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007322 (*in == '_') || (*in == '-') ||
7323 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007324 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007325 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007326 count = in - ctxt->cur;
7327 ret = xmlStrndup(ctxt->cur, count);
7328 ctxt->cur = in;
7329 return(ret);
7330 }
7331 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007332 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007333}
7334
Daniel Veillard61d80a22001-04-27 17:13:01 +00007335static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007336xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007337 xmlChar buf[XML_MAX_NAMELEN + 5];
7338 int len = 0, l;
7339 int c;
7340
7341 /*
7342 * Handler for more complex cases
7343 */
7344 c = CUR_CHAR(l);
7345 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007346 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7347 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007348 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007349 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007350 return(NULL);
7351 }
7352
7353 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7354 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7355 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007356 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007357 (IS_COMBINING(c)) ||
7358 (IS_EXTENDER(c)))) {
7359 COPY_BUF(l,buf,len,c);
7360 NEXTL(l);
7361 c = CUR_CHAR(l);
7362 if (len >= XML_MAX_NAMELEN) {
7363 /*
7364 * Okay someone managed to make a huge name, so he's ready to pay
7365 * for the processing speed.
7366 */
7367 xmlChar *buffer;
7368 int max = len * 2;
7369
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007370 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007371 if (buffer == NULL) {
7372 XP_ERROR0(XPATH_MEMORY_ERROR);
7373 }
7374 memcpy(buffer, buf, len);
7375 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7376 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007377 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007378 (IS_COMBINING(c)) ||
7379 (IS_EXTENDER(c))) {
7380 if (len + 10 > max) {
7381 max *= 2;
7382 buffer = (xmlChar *) xmlRealloc(buffer,
7383 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007384 if (buffer == NULL) {
7385 XP_ERROR0(XPATH_MEMORY_ERROR);
7386 }
7387 }
7388 COPY_BUF(l,buffer,len,c);
7389 NEXTL(l);
7390 c = CUR_CHAR(l);
7391 }
7392 buffer[len] = 0;
7393 return(buffer);
7394 }
7395 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007396 if (len == 0)
7397 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007398 return(xmlStrndup(buf, len));
7399}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007400
7401#define MAX_FRAC 20
7402
7403static double my_pow10[MAX_FRAC] = {
7404 1.0, 10.0, 100.0, 1000.0, 10000.0,
7405 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7406 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7407 100000000000000.0,
7408 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7409 1000000000000000000.0, 10000000000000000000.0
7410};
7411
Owen Taylor3473f882001-02-23 17:55:21 +00007412/**
7413 * xmlXPathStringEvalNumber:
7414 * @str: A string to scan
7415 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007416 * [30a] Float ::= Number ('e' Digits?)?
7417 *
Owen Taylor3473f882001-02-23 17:55:21 +00007418 * [30] Number ::= Digits ('.' Digits?)?
7419 * | '.' Digits
7420 * [31] Digits ::= [0-9]+
7421 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007422 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007423 * In complement of the Number expression, this function also handles
7424 * negative values : '-' Number.
7425 *
7426 * Returns the double value.
7427 */
7428double
7429xmlXPathStringEvalNumber(const xmlChar *str) {
7430 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007431 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007432 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007433 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007434 int exponent = 0;
7435 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007436#ifdef __GNUC__
7437 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007438 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007439#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007440 if (cur == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00007441 while (IS_BLANK(*cur)) cur++;
7442 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7443 return(xmlXPathNAN);
7444 }
7445 if (*cur == '-') {
7446 isneg = 1;
7447 cur++;
7448 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007449
7450#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007451 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007452 * tmp/temp is a workaround against a gcc compiler bug
7453 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007454 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007455 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007456 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007457 ret = ret * 10;
7458 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007459 ok = 1;
7460 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007461 temp = (double) tmp;
7462 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007463 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007464#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007465 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007466 while ((*cur >= '0') && (*cur <= '9')) {
7467 ret = ret * 10 + (*cur - '0');
7468 ok = 1;
7469 cur++;
7470 }
7471#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007472
Owen Taylor3473f882001-02-23 17:55:21 +00007473 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007474 int v, frac = 0;
7475 double fraction = 0;
7476
Owen Taylor3473f882001-02-23 17:55:21 +00007477 cur++;
7478 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7479 return(xmlXPathNAN);
7480 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007481 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7482 v = (*cur - '0');
7483 fraction = fraction * 10 + v;
7484 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007485 cur++;
7486 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007487 fraction /= my_pow10[frac];
7488 ret = ret + fraction;
7489 while ((*cur >= '0') && (*cur <= '9'))
7490 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007491 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007492 if ((*cur == 'e') || (*cur == 'E')) {
7493 cur++;
7494 if (*cur == '-') {
7495 is_exponent_negative = 1;
7496 cur++;
7497 }
7498 while ((*cur >= '0') && (*cur <= '9')) {
7499 exponent = exponent * 10 + (*cur - '0');
7500 cur++;
7501 }
7502 }
Owen Taylor3473f882001-02-23 17:55:21 +00007503 while (IS_BLANK(*cur)) cur++;
7504 if (*cur != 0) return(xmlXPathNAN);
7505 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007506 if (is_exponent_negative) exponent = -exponent;
7507 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007508 return(ret);
7509}
7510
7511/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007512 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007513 * @ctxt: the XPath Parser context
7514 *
7515 * [30] Number ::= Digits ('.' Digits?)?
7516 * | '.' Digits
7517 * [31] Digits ::= [0-9]+
7518 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007519 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007520 *
7521 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007522static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007523xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7524{
Owen Taylor3473f882001-02-23 17:55:21 +00007525 double ret = 0.0;
7526 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007527 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007528 int exponent = 0;
7529 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007530#ifdef __GNUC__
7531 unsigned long tmp = 0;
7532 double temp;
7533#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007534
7535 CHECK_ERROR;
7536 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7537 XP_ERROR(XPATH_NUMBER_ERROR);
7538 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007539#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007540 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007541 * tmp/temp is a workaround against a gcc compiler bug
7542 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007543 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007544 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007545 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007546 ret = ret * 10;
7547 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007548 ok = 1;
7549 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007550 temp = (double) tmp;
7551 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007552 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007553#else
7554 ret = 0;
7555 while ((CUR >= '0') && (CUR <= '9')) {
7556 ret = ret * 10 + (CUR - '0');
7557 ok = 1;
7558 NEXT;
7559 }
7560#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007561 if (CUR == '.') {
7562 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007563 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7564 XP_ERROR(XPATH_NUMBER_ERROR);
7565 }
7566 while ((CUR >= '0') && (CUR <= '9')) {
7567 mult /= 10;
7568 ret = ret + (CUR - '0') * mult;
7569 NEXT;
7570 }
Owen Taylor3473f882001-02-23 17:55:21 +00007571 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007572 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007573 NEXT;
7574 if (CUR == '-') {
7575 is_exponent_negative = 1;
7576 NEXT;
7577 }
7578 while ((CUR >= '0') && (CUR <= '9')) {
7579 exponent = exponent * 10 + (CUR - '0');
7580 NEXT;
7581 }
7582 if (is_exponent_negative)
7583 exponent = -exponent;
7584 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007585 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007586 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007587 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007588}
7589
7590/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007591 * xmlXPathParseLiteral:
7592 * @ctxt: the XPath Parser context
7593 *
7594 * Parse a Literal
7595 *
7596 * [29] Literal ::= '"' [^"]* '"'
7597 * | "'" [^']* "'"
7598 *
7599 * Returns the value found or NULL in case of error
7600 */
7601static xmlChar *
7602xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7603 const xmlChar *q;
7604 xmlChar *ret = NULL;
7605
7606 if (CUR == '"') {
7607 NEXT;
7608 q = CUR_PTR;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007609 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007610 NEXT;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007611 if (!IS_CHAR((unsigned int) CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007612 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7613 } else {
7614 ret = xmlStrndup(q, CUR_PTR - q);
7615 NEXT;
7616 }
7617 } else if (CUR == '\'') {
7618 NEXT;
7619 q = CUR_PTR;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007620 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007621 NEXT;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007622 if (!IS_CHAR((unsigned int) CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007623 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7624 } else {
7625 ret = xmlStrndup(q, CUR_PTR - q);
7626 NEXT;
7627 }
7628 } else {
7629 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7630 }
7631 return(ret);
7632}
7633
7634/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007635 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007636 * @ctxt: the XPath Parser context
7637 *
7638 * Parse a Literal and push it on the stack.
7639 *
7640 * [29] Literal ::= '"' [^"]* '"'
7641 * | "'" [^']* "'"
7642 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007643 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007644 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007645static void
7646xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007647 const xmlChar *q;
7648 xmlChar *ret = NULL;
7649
7650 if (CUR == '"') {
7651 NEXT;
7652 q = CUR_PTR;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007653 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007654 NEXT;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007655 if (!IS_CHAR((unsigned int) CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007656 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7657 } else {
7658 ret = xmlStrndup(q, CUR_PTR - q);
7659 NEXT;
7660 }
7661 } else if (CUR == '\'') {
7662 NEXT;
7663 q = CUR_PTR;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007664 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007665 NEXT;
Daniel Veillard34ba3872003-07-15 13:34:05 +00007666 if (!IS_CHAR((unsigned int) CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007667 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7668 } else {
7669 ret = xmlStrndup(q, CUR_PTR - q);
7670 NEXT;
7671 }
7672 } else {
7673 XP_ERROR(XPATH_START_LITERAL_ERROR);
7674 }
7675 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007676 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7677 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007678 xmlFree(ret);
7679}
7680
7681/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007682 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007683 * @ctxt: the XPath Parser context
7684 *
7685 * Parse a VariableReference, evaluate it and push it on the stack.
7686 *
7687 * The variable bindings consist of a mapping from variable names
7688 * to variable values. The value of a variable is an object, which
7689 * of any of the types that are possible for the value of an expression,
7690 * and may also be of additional types not specified here.
7691 *
7692 * Early evaluation is possible since:
7693 * The variable bindings [...] used to evaluate a subexpression are
7694 * always the same as those used to evaluate the containing expression.
7695 *
7696 * [36] VariableReference ::= '$' QName
7697 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007698static void
7699xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007700 xmlChar *name;
7701 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007702
7703 SKIP_BLANKS;
7704 if (CUR != '$') {
7705 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7706 }
7707 NEXT;
7708 name = xmlXPathParseQName(ctxt, &prefix);
7709 if (name == NULL) {
7710 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7711 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007712 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007713 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7714 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007715 SKIP_BLANKS;
7716}
7717
7718/**
7719 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007720 * @name: a name string
7721 *
7722 * Is the name given a NodeType one.
7723 *
7724 * [38] NodeType ::= 'comment'
7725 * | 'text'
7726 * | 'processing-instruction'
7727 * | 'node'
7728 *
7729 * Returns 1 if true 0 otherwise
7730 */
7731int
7732xmlXPathIsNodeType(const xmlChar *name) {
7733 if (name == NULL)
7734 return(0);
7735
Daniel Veillard1971ee22002-01-31 20:29:19 +00007736 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007737 return(1);
7738 if (xmlStrEqual(name, BAD_CAST "text"))
7739 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007740 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007741 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007742 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007743 return(1);
7744 return(0);
7745}
7746
7747/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007748 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007749 * @ctxt: the XPath Parser context
7750 *
7751 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7752 * [17] Argument ::= Expr
7753 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007754 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007755 * pushed on the stack
7756 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007757static void
7758xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007759 xmlChar *name;
7760 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007761 int nbargs = 0;
7762
7763 name = xmlXPathParseQName(ctxt, &prefix);
7764 if (name == NULL) {
7765 XP_ERROR(XPATH_EXPR_ERROR);
7766 }
7767 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007768#ifdef DEBUG_EXPR
7769 if (prefix == NULL)
7770 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7771 name);
7772 else
7773 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7774 prefix, name);
7775#endif
7776
Owen Taylor3473f882001-02-23 17:55:21 +00007777 if (CUR != '(') {
7778 XP_ERROR(XPATH_EXPR_ERROR);
7779 }
7780 NEXT;
7781 SKIP_BLANKS;
7782
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007783 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007784 if (CUR != ')') {
7785 while (CUR != 0) {
7786 int op1 = ctxt->comp->last;
7787 ctxt->comp->last = -1;
7788 xmlXPathCompileExpr(ctxt);
7789 CHECK_ERROR;
7790 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7791 nbargs++;
7792 if (CUR == ')') break;
7793 if (CUR != ',') {
7794 XP_ERROR(XPATH_EXPR_ERROR);
7795 }
7796 NEXT;
7797 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007798 }
Owen Taylor3473f882001-02-23 17:55:21 +00007799 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007800 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7801 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007802 NEXT;
7803 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007804}
7805
7806/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007807 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007808 * @ctxt: the XPath Parser context
7809 *
7810 * [15] PrimaryExpr ::= VariableReference
7811 * | '(' Expr ')'
7812 * | Literal
7813 * | Number
7814 * | FunctionCall
7815 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007816 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007817 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007818static void
7819xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007820 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007821 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007822 else if (CUR == '(') {
7823 NEXT;
7824 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007825 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007826 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007827 if (CUR != ')') {
7828 XP_ERROR(XPATH_EXPR_ERROR);
7829 }
7830 NEXT;
7831 SKIP_BLANKS;
Daniel Veillard01917aa2002-04-10 11:30:41 +00007832 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007833 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007834 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007835 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007836 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007837 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007838 }
7839 SKIP_BLANKS;
7840}
7841
7842/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007843 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007844 * @ctxt: the XPath Parser context
7845 *
7846 * [20] FilterExpr ::= PrimaryExpr
7847 * | FilterExpr Predicate
7848 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007849 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007850 * Square brackets are used to filter expressions in the same way that
7851 * they are used in location paths. It is an error if the expression to
7852 * be filtered does not evaluate to a node-set. The context node list
7853 * used for evaluating the expression in square brackets is the node-set
7854 * to be filtered listed in document order.
7855 */
7856
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007857static void
7858xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7859 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007860 CHECK_ERROR;
7861 SKIP_BLANKS;
7862
7863 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007864 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007865 SKIP_BLANKS;
7866 }
7867
7868
7869}
7870
7871/**
7872 * xmlXPathScanName:
7873 * @ctxt: the XPath Parser context
7874 *
7875 * Trickery: parse an XML name but without consuming the input flow
7876 * Needed to avoid insanity in the parser state.
7877 *
7878 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7879 * CombiningChar | Extender
7880 *
7881 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7882 *
7883 * [6] Names ::= Name (S Name)*
7884 *
7885 * Returns the Name parsed or NULL
7886 */
7887
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007888static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007889xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7890 xmlChar buf[XML_MAX_NAMELEN];
7891 int len = 0;
7892
7893 SKIP_BLANKS;
7894 if (!IS_LETTER(CUR) && (CUR != '_') &&
7895 (CUR != ':')) {
7896 return(NULL);
7897 }
7898
7899 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7900 (NXT(len) == '.') || (NXT(len) == '-') ||
7901 (NXT(len) == '_') || (NXT(len) == ':') ||
7902 (IS_COMBINING(NXT(len))) ||
7903 (IS_EXTENDER(NXT(len)))) {
7904 buf[len] = NXT(len);
7905 len++;
7906 if (len >= XML_MAX_NAMELEN) {
7907 xmlGenericError(xmlGenericErrorContext,
7908 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7909 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7910 (NXT(len) == '.') || (NXT(len) == '-') ||
7911 (NXT(len) == '_') || (NXT(len) == ':') ||
7912 (IS_COMBINING(NXT(len))) ||
7913 (IS_EXTENDER(NXT(len))))
7914 len++;
7915 break;
7916 }
7917 }
7918 return(xmlStrndup(buf, len));
7919}
7920
7921/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007922 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007923 * @ctxt: the XPath Parser context
7924 *
7925 * [19] PathExpr ::= LocationPath
7926 * | FilterExpr
7927 * | FilterExpr '/' RelativeLocationPath
7928 * | FilterExpr '//' RelativeLocationPath
7929 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007930 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007931 * The / operator and // operators combine an arbitrary expression
7932 * and a relative location path. It is an error if the expression
7933 * does not evaluate to a node-set.
7934 * The / operator does composition in the same way as when / is
7935 * used in a location path. As in location paths, // is short for
7936 * /descendant-or-self::node()/.
7937 */
7938
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007939static void
7940xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007941 int lc = 1; /* Should we branch to LocationPath ? */
7942 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7943
7944 SKIP_BLANKS;
7945 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
Daniel Veillard01917aa2002-04-10 11:30:41 +00007946 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007947 lc = 0;
7948 } else if (CUR == '*') {
7949 /* relative or absolute location path */
7950 lc = 1;
7951 } else if (CUR == '/') {
7952 /* relative or absolute location path */
7953 lc = 1;
7954 } else if (CUR == '@') {
7955 /* relative abbreviated attribute location path */
7956 lc = 1;
7957 } else if (CUR == '.') {
7958 /* relative abbreviated attribute location path */
7959 lc = 1;
7960 } else {
7961 /*
7962 * Problem is finding if we have a name here whether it's:
7963 * - a nodetype
7964 * - a function call in which case it's followed by '('
7965 * - an axis in which case it's followed by ':'
7966 * - a element name
7967 * We do an a priori analysis here rather than having to
7968 * maintain parsed token content through the recursive function
7969 * calls. This looks uglier but makes the code quite easier to
7970 * read/write/debug.
7971 */
7972 SKIP_BLANKS;
7973 name = xmlXPathScanName(ctxt);
7974 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7975#ifdef DEBUG_STEP
7976 xmlGenericError(xmlGenericErrorContext,
7977 "PathExpr: Axis\n");
7978#endif
7979 lc = 1;
7980 xmlFree(name);
7981 } else if (name != NULL) {
7982 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00007983
7984
7985 while (NXT(len) != 0) {
7986 if (NXT(len) == '/') {
7987 /* element name */
7988#ifdef DEBUG_STEP
7989 xmlGenericError(xmlGenericErrorContext,
7990 "PathExpr: AbbrRelLocation\n");
7991#endif
7992 lc = 1;
7993 break;
7994 } else if (IS_BLANK(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00007995 /* ignore blanks */
7996 ;
Owen Taylor3473f882001-02-23 17:55:21 +00007997 } else if (NXT(len) == ':') {
7998#ifdef DEBUG_STEP
7999 xmlGenericError(xmlGenericErrorContext,
8000 "PathExpr: AbbrRelLocation\n");
8001#endif
8002 lc = 1;
8003 break;
8004 } else if ((NXT(len) == '(')) {
8005 /* Note Type or Function */
8006 if (xmlXPathIsNodeType(name)) {
8007#ifdef DEBUG_STEP
8008 xmlGenericError(xmlGenericErrorContext,
8009 "PathExpr: Type search\n");
8010#endif
8011 lc = 1;
8012 } else {
8013#ifdef DEBUG_STEP
8014 xmlGenericError(xmlGenericErrorContext,
8015 "PathExpr: function call\n");
8016#endif
8017 lc = 0;
8018 }
8019 break;
8020 } else if ((NXT(len) == '[')) {
8021 /* element name */
8022#ifdef DEBUG_STEP
8023 xmlGenericError(xmlGenericErrorContext,
8024 "PathExpr: AbbrRelLocation\n");
8025#endif
8026 lc = 1;
8027 break;
8028 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8029 (NXT(len) == '=')) {
8030 lc = 1;
8031 break;
8032 } else {
8033 lc = 1;
8034 break;
8035 }
8036 len++;
8037 }
8038 if (NXT(len) == 0) {
8039#ifdef DEBUG_STEP
8040 xmlGenericError(xmlGenericErrorContext,
8041 "PathExpr: AbbrRelLocation\n");
8042#endif
8043 /* element name */
8044 lc = 1;
8045 }
8046 xmlFree(name);
8047 } else {
8048 /* make sure all cases are covered explicitely */
8049 XP_ERROR(XPATH_EXPR_ERROR);
8050 }
8051 }
8052
8053 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008054 if (CUR == '/') {
8055 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8056 } else {
8057 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008058 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008059 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008060 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008061 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008062 CHECK_ERROR;
8063 if ((CUR == '/') && (NXT(1) == '/')) {
8064 SKIP(2);
8065 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008066
8067 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8068 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8069 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8070
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008071 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008072 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008073 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008074 }
8075 }
8076 SKIP_BLANKS;
8077}
8078
8079/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008080 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008081 * @ctxt: the XPath Parser context
8082 *
8083 * [18] UnionExpr ::= PathExpr
8084 * | UnionExpr '|' PathExpr
8085 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008086 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008087 */
8088
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008089static void
8090xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8091 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008092 CHECK_ERROR;
8093 SKIP_BLANKS;
8094 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008095 int op1 = ctxt->comp->last;
8096 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008097
8098 NEXT;
8099 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008100 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008101
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008102 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8103
Owen Taylor3473f882001-02-23 17:55:21 +00008104 SKIP_BLANKS;
8105 }
Owen Taylor3473f882001-02-23 17:55:21 +00008106}
8107
8108/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008109 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008110 * @ctxt: the XPath Parser context
8111 *
8112 * [27] UnaryExpr ::= UnionExpr
8113 * | '-' UnaryExpr
8114 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008115 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008116 */
8117
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008118static void
8119xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008120 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008121 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008122
8123 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008124 while (CUR == '-') {
8125 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008126 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008127 NEXT;
8128 SKIP_BLANKS;
8129 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008130
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008131 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008132 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008133 if (found) {
8134 if (minus)
8135 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8136 else
8137 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008138 }
8139}
8140
8141/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008142 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008143 * @ctxt: the XPath Parser context
8144 *
8145 * [26] MultiplicativeExpr ::= UnaryExpr
8146 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8147 * | MultiplicativeExpr 'div' UnaryExpr
8148 * | MultiplicativeExpr 'mod' UnaryExpr
8149 * [34] MultiplyOperator ::= '*'
8150 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008151 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008152 */
8153
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008154static void
8155xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8156 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008157 CHECK_ERROR;
8158 SKIP_BLANKS;
8159 while ((CUR == '*') ||
8160 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8161 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8162 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008163 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008164
8165 if (CUR == '*') {
8166 op = 0;
8167 NEXT;
8168 } else if (CUR == 'd') {
8169 op = 1;
8170 SKIP(3);
8171 } else if (CUR == 'm') {
8172 op = 2;
8173 SKIP(3);
8174 }
8175 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008176 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008177 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008178 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008179 SKIP_BLANKS;
8180 }
8181}
8182
8183/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008184 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008185 * @ctxt: the XPath Parser context
8186 *
8187 * [25] AdditiveExpr ::= MultiplicativeExpr
8188 * | AdditiveExpr '+' MultiplicativeExpr
8189 * | AdditiveExpr '-' MultiplicativeExpr
8190 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008191 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008192 */
8193
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008194static void
8195xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008196
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008197 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008198 CHECK_ERROR;
8199 SKIP_BLANKS;
8200 while ((CUR == '+') || (CUR == '-')) {
8201 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008202 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008203
8204 if (CUR == '+') plus = 1;
8205 else plus = 0;
8206 NEXT;
8207 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008208 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008209 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008210 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008211 SKIP_BLANKS;
8212 }
8213}
8214
8215/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008216 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008217 * @ctxt: the XPath Parser context
8218 *
8219 * [24] RelationalExpr ::= AdditiveExpr
8220 * | RelationalExpr '<' AdditiveExpr
8221 * | RelationalExpr '>' AdditiveExpr
8222 * | RelationalExpr '<=' AdditiveExpr
8223 * | RelationalExpr '>=' AdditiveExpr
8224 *
8225 * A <= B > C is allowed ? Answer from James, yes with
8226 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8227 * which is basically what got implemented.
8228 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008229 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008230 * on the stack
8231 */
8232
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008233static void
8234xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8235 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008236 CHECK_ERROR;
8237 SKIP_BLANKS;
8238 while ((CUR == '<') ||
8239 (CUR == '>') ||
8240 ((CUR == '<') && (NXT(1) == '=')) ||
8241 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008242 int inf, strict;
8243 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008244
8245 if (CUR == '<') inf = 1;
8246 else inf = 0;
8247 if (NXT(1) == '=') strict = 0;
8248 else strict = 1;
8249 NEXT;
8250 if (!strict) NEXT;
8251 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008252 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008253 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008254 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008255 SKIP_BLANKS;
8256 }
8257}
8258
8259/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008260 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008261 * @ctxt: the XPath Parser context
8262 *
8263 * [23] EqualityExpr ::= RelationalExpr
8264 * | EqualityExpr '=' RelationalExpr
8265 * | EqualityExpr '!=' RelationalExpr
8266 *
8267 * A != B != C is allowed ? Answer from James, yes with
8268 * (RelationalExpr = RelationalExpr) = RelationalExpr
8269 * (RelationalExpr != RelationalExpr) != RelationalExpr
8270 * which is basically what got implemented.
8271 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008272 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008273 *
8274 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008275static void
8276xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8277 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008278 CHECK_ERROR;
8279 SKIP_BLANKS;
8280 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008281 int eq;
8282 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008283
8284 if (CUR == '=') eq = 1;
8285 else eq = 0;
8286 NEXT;
8287 if (!eq) NEXT;
8288 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008289 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008290 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008291 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008292 SKIP_BLANKS;
8293 }
8294}
8295
8296/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008297 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008298 * @ctxt: the XPath Parser context
8299 *
8300 * [22] AndExpr ::= EqualityExpr
8301 * | AndExpr 'and' EqualityExpr
8302 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008303 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008304 *
8305 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008306static void
8307xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8308 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008309 CHECK_ERROR;
8310 SKIP_BLANKS;
8311 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008312 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008313 SKIP(3);
8314 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008315 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008316 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008317 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008318 SKIP_BLANKS;
8319 }
8320}
8321
8322/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008323 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008324 * @ctxt: the XPath Parser context
8325 *
8326 * [14] Expr ::= OrExpr
8327 * [21] OrExpr ::= AndExpr
8328 * | OrExpr 'or' AndExpr
8329 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008330 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008331 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008332static void
8333xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8334 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008335 CHECK_ERROR;
8336 SKIP_BLANKS;
8337 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008338 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008339 SKIP(2);
8340 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008341 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008342 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008343 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8344 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008345 SKIP_BLANKS;
8346 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008347 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8348 /* more ops could be optimized too */
8349 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8350 }
Owen Taylor3473f882001-02-23 17:55:21 +00008351}
8352
8353/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008354 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008355 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008356 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008357 *
8358 * [8] Predicate ::= '[' PredicateExpr ']'
8359 * [9] PredicateExpr ::= Expr
8360 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008361 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008362 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008363static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008364xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008365 int op1 = ctxt->comp->last;
8366
8367 SKIP_BLANKS;
8368 if (CUR != '[') {
8369 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8370 }
8371 NEXT;
8372 SKIP_BLANKS;
8373
8374 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008375 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008376 CHECK_ERROR;
8377
8378 if (CUR != ']') {
8379 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8380 }
8381
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008382 if (filter)
8383 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8384 else
8385 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008386
8387 NEXT;
8388 SKIP_BLANKS;
8389}
8390
8391/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008392 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008393 * @ctxt: the XPath Parser context
8394 * @test: pointer to a xmlXPathTestVal
8395 * @type: pointer to a xmlXPathTypeVal
8396 * @prefix: placeholder for a possible name prefix
8397 *
8398 * [7] NodeTest ::= NameTest
8399 * | NodeType '(' ')'
8400 * | 'processing-instruction' '(' Literal ')'
8401 *
8402 * [37] NameTest ::= '*'
8403 * | NCName ':' '*'
8404 * | QName
8405 * [38] NodeType ::= 'comment'
8406 * | 'text'
8407 * | 'processing-instruction'
8408 * | 'node'
8409 *
8410 * Returns the name found and update @test, @type and @prefix appropriately
8411 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008412static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008413xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8414 xmlXPathTypeVal *type, const xmlChar **prefix,
8415 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008416 int blanks;
8417
8418 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8419 STRANGE;
8420 return(NULL);
8421 }
William M. Brack78637da2003-07-31 14:47:38 +00008422 *type = (xmlXPathTypeVal) 0;
8423 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008424 *prefix = NULL;
8425 SKIP_BLANKS;
8426
8427 if ((name == NULL) && (CUR == '*')) {
8428 /*
8429 * All elements
8430 */
8431 NEXT;
8432 *test = NODE_TEST_ALL;
8433 return(NULL);
8434 }
8435
8436 if (name == NULL)
8437 name = xmlXPathParseNCName(ctxt);
8438 if (name == NULL) {
8439 XP_ERROR0(XPATH_EXPR_ERROR);
8440 }
8441
8442 blanks = IS_BLANK(CUR);
8443 SKIP_BLANKS;
8444 if (CUR == '(') {
8445 NEXT;
8446 /*
8447 * NodeType or PI search
8448 */
8449 if (xmlStrEqual(name, BAD_CAST "comment"))
8450 *type = NODE_TYPE_COMMENT;
8451 else if (xmlStrEqual(name, BAD_CAST "node"))
8452 *type = NODE_TYPE_NODE;
8453 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8454 *type = NODE_TYPE_PI;
8455 else if (xmlStrEqual(name, BAD_CAST "text"))
8456 *type = NODE_TYPE_TEXT;
8457 else {
8458 if (name != NULL)
8459 xmlFree(name);
8460 XP_ERROR0(XPATH_EXPR_ERROR);
8461 }
8462
8463 *test = NODE_TEST_TYPE;
8464
8465 SKIP_BLANKS;
8466 if (*type == NODE_TYPE_PI) {
8467 /*
8468 * Specific case: search a PI by name.
8469 */
Owen Taylor3473f882001-02-23 17:55:21 +00008470 if (name != NULL)
8471 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008472 name = NULL;
8473 if (CUR != ')') {
8474 name = xmlXPathParseLiteral(ctxt);
8475 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008476 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008477 SKIP_BLANKS;
8478 }
Owen Taylor3473f882001-02-23 17:55:21 +00008479 }
8480 if (CUR != ')') {
8481 if (name != NULL)
8482 xmlFree(name);
8483 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8484 }
8485 NEXT;
8486 return(name);
8487 }
8488 *test = NODE_TEST_NAME;
8489 if ((!blanks) && (CUR == ':')) {
8490 NEXT;
8491
8492 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008493 * Since currently the parser context don't have a
8494 * namespace list associated:
8495 * The namespace name for this prefix can be computed
8496 * only at evaluation time. The compilation is done
8497 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008498 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008499#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008500 *prefix = xmlXPathNsLookup(ctxt->context, name);
8501 if (name != NULL)
8502 xmlFree(name);
8503 if (*prefix == NULL) {
8504 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8505 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008506#else
8507 *prefix = name;
8508#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008509
8510 if (CUR == '*') {
8511 /*
8512 * All elements
8513 */
8514 NEXT;
8515 *test = NODE_TEST_ALL;
8516 return(NULL);
8517 }
8518
8519 name = xmlXPathParseNCName(ctxt);
8520 if (name == NULL) {
8521 XP_ERROR0(XPATH_EXPR_ERROR);
8522 }
8523 }
8524 return(name);
8525}
8526
8527/**
8528 * xmlXPathIsAxisName:
8529 * @name: a preparsed name token
8530 *
8531 * [6] AxisName ::= 'ancestor'
8532 * | 'ancestor-or-self'
8533 * | 'attribute'
8534 * | 'child'
8535 * | 'descendant'
8536 * | 'descendant-or-self'
8537 * | 'following'
8538 * | 'following-sibling'
8539 * | 'namespace'
8540 * | 'parent'
8541 * | 'preceding'
8542 * | 'preceding-sibling'
8543 * | 'self'
8544 *
8545 * Returns the axis or 0
8546 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008547static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008548xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008549 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008550 switch (name[0]) {
8551 case 'a':
8552 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8553 ret = AXIS_ANCESTOR;
8554 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8555 ret = AXIS_ANCESTOR_OR_SELF;
8556 if (xmlStrEqual(name, BAD_CAST "attribute"))
8557 ret = AXIS_ATTRIBUTE;
8558 break;
8559 case 'c':
8560 if (xmlStrEqual(name, BAD_CAST "child"))
8561 ret = AXIS_CHILD;
8562 break;
8563 case 'd':
8564 if (xmlStrEqual(name, BAD_CAST "descendant"))
8565 ret = AXIS_DESCENDANT;
8566 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8567 ret = AXIS_DESCENDANT_OR_SELF;
8568 break;
8569 case 'f':
8570 if (xmlStrEqual(name, BAD_CAST "following"))
8571 ret = AXIS_FOLLOWING;
8572 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8573 ret = AXIS_FOLLOWING_SIBLING;
8574 break;
8575 case 'n':
8576 if (xmlStrEqual(name, BAD_CAST "namespace"))
8577 ret = AXIS_NAMESPACE;
8578 break;
8579 case 'p':
8580 if (xmlStrEqual(name, BAD_CAST "parent"))
8581 ret = AXIS_PARENT;
8582 if (xmlStrEqual(name, BAD_CAST "preceding"))
8583 ret = AXIS_PRECEDING;
8584 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8585 ret = AXIS_PRECEDING_SIBLING;
8586 break;
8587 case 's':
8588 if (xmlStrEqual(name, BAD_CAST "self"))
8589 ret = AXIS_SELF;
8590 break;
8591 }
8592 return(ret);
8593}
8594
8595/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008596 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008597 * @ctxt: the XPath Parser context
8598 *
8599 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8600 * | AbbreviatedStep
8601 *
8602 * [12] AbbreviatedStep ::= '.' | '..'
8603 *
8604 * [5] AxisSpecifier ::= AxisName '::'
8605 * | AbbreviatedAxisSpecifier
8606 *
8607 * [13] AbbreviatedAxisSpecifier ::= '@'?
8608 *
8609 * Modified for XPtr range support as:
8610 *
8611 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8612 * | AbbreviatedStep
8613 * | 'range-to' '(' Expr ')' Predicate*
8614 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008615 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008616 * A location step of . is short for self::node(). This is
8617 * particularly useful in conjunction with //. For example, the
8618 * location path .//para is short for
8619 * self::node()/descendant-or-self::node()/child::para
8620 * and so will select all para descendant elements of the context
8621 * node.
8622 * Similarly, a location step of .. is short for parent::node().
8623 * For example, ../title is short for parent::node()/child::title
8624 * and so will select the title children of the parent of the context
8625 * node.
8626 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008627static void
8628xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008629#ifdef LIBXML_XPTR_ENABLED
8630 int rangeto = 0;
8631 int op2 = -1;
8632#endif
8633
Owen Taylor3473f882001-02-23 17:55:21 +00008634 SKIP_BLANKS;
8635 if ((CUR == '.') && (NXT(1) == '.')) {
8636 SKIP(2);
8637 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008638 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8639 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008640 } else if (CUR == '.') {
8641 NEXT;
8642 SKIP_BLANKS;
8643 } else {
8644 xmlChar *name = NULL;
8645 const xmlChar *prefix = NULL;
8646 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008647 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008648 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008649 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008650
8651 /*
8652 * The modification needed for XPointer change to the production
8653 */
8654#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008655 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008656 name = xmlXPathParseNCName(ctxt);
8657 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008658 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008659 xmlFree(name);
8660 SKIP_BLANKS;
8661 if (CUR != '(') {
8662 XP_ERROR(XPATH_EXPR_ERROR);
8663 }
8664 NEXT;
8665 SKIP_BLANKS;
8666
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008667 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008668 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008669 CHECK_ERROR;
8670
8671 SKIP_BLANKS;
8672 if (CUR != ')') {
8673 XP_ERROR(XPATH_EXPR_ERROR);
8674 }
8675 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008676 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008677 goto eval_predicates;
8678 }
8679 }
8680#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008681 if (CUR == '*') {
8682 axis = AXIS_CHILD;
8683 } else {
8684 if (name == NULL)
8685 name = xmlXPathParseNCName(ctxt);
8686 if (name != NULL) {
8687 axis = xmlXPathIsAxisName(name);
8688 if (axis != 0) {
8689 SKIP_BLANKS;
8690 if ((CUR == ':') && (NXT(1) == ':')) {
8691 SKIP(2);
8692 xmlFree(name);
8693 name = NULL;
8694 } else {
8695 /* an element name can conflict with an axis one :-\ */
8696 axis = AXIS_CHILD;
8697 }
Owen Taylor3473f882001-02-23 17:55:21 +00008698 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008699 axis = AXIS_CHILD;
8700 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008701 } else if (CUR == '@') {
8702 NEXT;
8703 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008704 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008705 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008706 }
Owen Taylor3473f882001-02-23 17:55:21 +00008707 }
8708
8709 CHECK_ERROR;
8710
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008711 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008712 if (test == 0)
8713 return;
8714
8715#ifdef DEBUG_STEP
8716 xmlGenericError(xmlGenericErrorContext,
8717 "Basis : computing new set\n");
8718#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008719
Owen Taylor3473f882001-02-23 17:55:21 +00008720#ifdef DEBUG_STEP
8721 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008722 if (ctxt->value == NULL)
8723 xmlGenericError(xmlGenericErrorContext, "no value\n");
8724 else if (ctxt->value->nodesetval == NULL)
8725 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8726 else
8727 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008728#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008729
8730eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008731 op1 = ctxt->comp->last;
8732 ctxt->comp->last = -1;
8733
Owen Taylor3473f882001-02-23 17:55:21 +00008734 SKIP_BLANKS;
8735 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008736 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008737 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008738
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008739#ifdef LIBXML_XPTR_ENABLED
8740 if (rangeto) {
8741 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8742 } else
8743#endif
8744 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8745 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008746
Owen Taylor3473f882001-02-23 17:55:21 +00008747 }
8748#ifdef DEBUG_STEP
8749 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008750 if (ctxt->value == NULL)
8751 xmlGenericError(xmlGenericErrorContext, "no value\n");
8752 else if (ctxt->value->nodesetval == NULL)
8753 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8754 else
8755 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8756 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008757#endif
8758}
8759
8760/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008761 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008762 * @ctxt: the XPath Parser context
8763 *
8764 * [3] RelativeLocationPath ::= Step
8765 * | RelativeLocationPath '/' Step
8766 * | AbbreviatedRelativeLocationPath
8767 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8768 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008769 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008770 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008771static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008772xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008773(xmlXPathParserContextPtr ctxt) {
8774 SKIP_BLANKS;
8775 if ((CUR == '/') && (NXT(1) == '/')) {
8776 SKIP(2);
8777 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008778 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8779 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008780 } else if (CUR == '/') {
8781 NEXT;
8782 SKIP_BLANKS;
8783 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008784 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008785 SKIP_BLANKS;
8786 while (CUR == '/') {
8787 if ((CUR == '/') && (NXT(1) == '/')) {
8788 SKIP(2);
8789 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008790 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008791 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008792 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008793 } else if (CUR == '/') {
8794 NEXT;
8795 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008796 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008797 }
8798 SKIP_BLANKS;
8799 }
8800}
8801
8802/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008803 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008804 * @ctxt: the XPath Parser context
8805 *
8806 * [1] LocationPath ::= RelativeLocationPath
8807 * | AbsoluteLocationPath
8808 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8809 * | AbbreviatedAbsoluteLocationPath
8810 * [10] AbbreviatedAbsoluteLocationPath ::=
8811 * '//' RelativeLocationPath
8812 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008813 * Compile a location path
8814 *
Owen Taylor3473f882001-02-23 17:55:21 +00008815 * // is short for /descendant-or-self::node()/. For example,
8816 * //para is short for /descendant-or-self::node()/child::para and
8817 * so will select any para element in the document (even a para element
8818 * that is a document element will be selected by //para since the
8819 * document element node is a child of the root node); div//para is
8820 * short for div/descendant-or-self::node()/child::para and so will
8821 * select all para descendants of div children.
8822 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008823static void
8824xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008825 SKIP_BLANKS;
8826 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008827 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008828 } else {
8829 while (CUR == '/') {
8830 if ((CUR == '/') && (NXT(1) == '/')) {
8831 SKIP(2);
8832 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008833 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8834 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008835 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008836 } else if (CUR == '/') {
8837 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008838 SKIP_BLANKS;
8839 if ((CUR != 0 ) &&
8840 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8841 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008842 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008843 }
8844 }
8845 }
8846}
8847
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008848/************************************************************************
8849 * *
8850 * XPath precompiled expression evaluation *
8851 * *
8852 ************************************************************************/
8853
Daniel Veillardf06307e2001-07-03 10:35:50 +00008854static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008855xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8856
8857/**
8858 * xmlXPathNodeCollectAndTest:
8859 * @ctxt: the XPath Parser context
8860 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008861 * @first: pointer to the first element in document order
8862 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008863 *
8864 * This is the function implementing a step: based on the current list
8865 * of nodes, it builds up a new list, looking at all nodes under that
8866 * axis and selecting them it also do the predicate filtering
8867 *
8868 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008869 *
8870 * Returns the number of node traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008871 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008872static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008873xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008874 xmlXPathStepOpPtr op,
8875 xmlNodePtr * first, xmlNodePtr * last)
8876{
William M. Brack78637da2003-07-31 14:47:38 +00008877 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
8878 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
8879 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008880 const xmlChar *prefix = op->value4;
8881 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008882 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008883
8884#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008885 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008886#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008887 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008888 xmlNodeSetPtr ret, list;
8889 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008890 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008891 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008892 xmlNodePtr cur = NULL;
8893 xmlXPathObjectPtr obj;
8894 xmlNodeSetPtr nodelist;
8895 xmlNodePtr tmp;
8896
Daniel Veillardf06307e2001-07-03 10:35:50 +00008897 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008898 obj = valuePop(ctxt);
8899 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008900 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008901 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008902 URI = xmlXPathNsLookup(ctxt->context, prefix);
8903 if (URI == NULL)
8904 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008905 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008906#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008907 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008908#endif
8909 switch (axis) {
8910 case AXIS_ANCESTOR:
8911#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008912 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008913#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008914 first = NULL;
8915 next = xmlXPathNextAncestor;
8916 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008917 case AXIS_ANCESTOR_OR_SELF:
8918#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008919 xmlGenericError(xmlGenericErrorContext,
8920 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008921#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008922 first = NULL;
8923 next = xmlXPathNextAncestorOrSelf;
8924 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008925 case AXIS_ATTRIBUTE:
8926#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008927 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008928#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008929 first = NULL;
8930 last = NULL;
8931 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008932 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008933 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008934 case AXIS_CHILD:
8935#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008936 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008937#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008938 last = NULL;
8939 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008940 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008941 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008942 case AXIS_DESCENDANT:
8943#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008944 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008945#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008946 last = NULL;
8947 next = xmlXPathNextDescendant;
8948 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008949 case AXIS_DESCENDANT_OR_SELF:
8950#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008951 xmlGenericError(xmlGenericErrorContext,
8952 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008953#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008954 last = NULL;
8955 next = xmlXPathNextDescendantOrSelf;
8956 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008957 case AXIS_FOLLOWING:
8958#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008959 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008960#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008961 last = NULL;
8962 next = xmlXPathNextFollowing;
8963 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008964 case AXIS_FOLLOWING_SIBLING:
8965#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008966 xmlGenericError(xmlGenericErrorContext,
8967 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008968#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008969 last = NULL;
8970 next = xmlXPathNextFollowingSibling;
8971 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008972 case AXIS_NAMESPACE:
8973#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008974 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008975#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008976 first = NULL;
8977 last = NULL;
8978 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00008979 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008980 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008981 case AXIS_PARENT:
8982#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008983 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008984#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008985 first = NULL;
8986 next = xmlXPathNextParent;
8987 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008988 case AXIS_PRECEDING:
8989#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008990 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008991#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008992 first = NULL;
8993 next = xmlXPathNextPrecedingInternal;
8994 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008995 case AXIS_PRECEDING_SIBLING:
8996#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008997 xmlGenericError(xmlGenericErrorContext,
8998 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008999#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009000 first = NULL;
9001 next = xmlXPathNextPrecedingSibling;
9002 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009003 case AXIS_SELF:
9004#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009005 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009006#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009007 first = NULL;
9008 last = NULL;
9009 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009010 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009011 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009012 }
9013 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009014 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009015
9016 nodelist = obj->nodesetval;
9017 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009018 xmlXPathFreeObject(obj);
9019 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9020 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009021 }
9022 addNode = xmlXPathNodeSetAddUnique;
9023 ret = NULL;
9024#ifdef DEBUG_STEP
9025 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009026 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009027 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009028 case NODE_TEST_NONE:
9029 xmlGenericError(xmlGenericErrorContext,
9030 " searching for none !!!\n");
9031 break;
9032 case NODE_TEST_TYPE:
9033 xmlGenericError(xmlGenericErrorContext,
9034 " searching for type %d\n", type);
9035 break;
9036 case NODE_TEST_PI:
9037 xmlGenericError(xmlGenericErrorContext,
9038 " searching for PI !!!\n");
9039 break;
9040 case NODE_TEST_ALL:
9041 xmlGenericError(xmlGenericErrorContext,
9042 " searching for *\n");
9043 break;
9044 case NODE_TEST_NS:
9045 xmlGenericError(xmlGenericErrorContext,
9046 " searching for namespace %s\n",
9047 prefix);
9048 break;
9049 case NODE_TEST_NAME:
9050 xmlGenericError(xmlGenericErrorContext,
9051 " searching for name %s\n", name);
9052 if (prefix != NULL)
9053 xmlGenericError(xmlGenericErrorContext,
9054 " with namespace %s\n", prefix);
9055 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009056 }
9057 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9058#endif
9059 /*
9060 * 2.3 Node Tests
9061 * - For the attribute axis, the principal node type is attribute.
9062 * - For the namespace axis, the principal node type is namespace.
9063 * - For other axes, the principal node type is element.
9064 *
9065 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009066 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009067 * select all element children of the context node
9068 */
9069 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009070 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009071 ctxt->context->node = nodelist->nodeTab[i];
9072
Daniel Veillardf06307e2001-07-03 10:35:50 +00009073 cur = NULL;
9074 list = xmlXPathNodeSetCreate(NULL);
9075 do {
9076 cur = next(ctxt, cur);
9077 if (cur == NULL)
9078 break;
9079 if ((first != NULL) && (*first == cur))
9080 break;
9081 if (((t % 256) == 0) &&
9082 (first != NULL) && (*first != NULL) &&
9083 (xmlXPathCmpNodes(*first, cur) >= 0))
9084 break;
9085 if ((last != NULL) && (*last == cur))
9086 break;
9087 if (((t % 256) == 0) &&
9088 (last != NULL) && (*last != NULL) &&
9089 (xmlXPathCmpNodes(cur, *last) >= 0))
9090 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009091 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009092#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009093 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9094#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009095 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009096 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009097 ctxt->context->node = tmp;
9098 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009099 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009100 if ((cur->type == type) ||
9101 ((type == NODE_TYPE_NODE) &&
9102 ((cur->type == XML_DOCUMENT_NODE) ||
9103 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9104 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009105 (cur->type == XML_NAMESPACE_DECL) ||
9106 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009107 (cur->type == XML_PI_NODE) ||
9108 (cur->type == XML_COMMENT_NODE) ||
9109 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009110 (cur->type == XML_TEXT_NODE))) ||
9111 ((type == NODE_TYPE_TEXT) &&
9112 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009113#ifdef DEBUG_STEP
9114 n++;
9115#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009116 addNode(list, cur);
9117 }
9118 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009119 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009120 if (cur->type == XML_PI_NODE) {
9121 if ((name != NULL) &&
9122 (!xmlStrEqual(name, cur->name)))
9123 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009124#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009125 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009126#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009127 addNode(list, cur);
9128 }
9129 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009130 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009131 if (axis == AXIS_ATTRIBUTE) {
9132 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009133#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009134 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009135#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009136 addNode(list, cur);
9137 }
9138 } else if (axis == AXIS_NAMESPACE) {
9139 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009140#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009141 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009142#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009143 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9144 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009145 }
9146 } else {
9147 if (cur->type == XML_ELEMENT_NODE) {
9148 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009149#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009150 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009151#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009152 addNode(list, cur);
9153 } else if ((cur->ns != NULL) &&
9154 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009155#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009156 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009157#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009158 addNode(list, cur);
9159 }
9160 }
9161 }
9162 break;
9163 case NODE_TEST_NS:{
9164 TODO;
9165 break;
9166 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009167 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009168 switch (cur->type) {
9169 case XML_ELEMENT_NODE:
9170 if (xmlStrEqual(name, cur->name)) {
9171 if (prefix == NULL) {
9172 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009173#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009174 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009175#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009176 addNode(list, cur);
9177 }
9178 } else {
9179 if ((cur->ns != NULL) &&
9180 (xmlStrEqual(URI,
9181 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009182#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009183 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009184#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009185 addNode(list, cur);
9186 }
9187 }
9188 }
9189 break;
9190 case XML_ATTRIBUTE_NODE:{
9191 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009192
Daniel Veillardf06307e2001-07-03 10:35:50 +00009193 if (xmlStrEqual(name, attr->name)) {
9194 if (prefix == NULL) {
9195 if ((attr->ns == NULL) ||
9196 (attr->ns->prefix == NULL)) {
9197#ifdef DEBUG_STEP
9198 n++;
9199#endif
9200 addNode(list,
9201 (xmlNodePtr) attr);
9202 }
9203 } else {
9204 if ((attr->ns != NULL) &&
9205 (xmlStrEqual(URI,
9206 attr->ns->
9207 href))) {
9208#ifdef DEBUG_STEP
9209 n++;
9210#endif
9211 addNode(list,
9212 (xmlNodePtr) attr);
9213 }
9214 }
9215 }
9216 break;
9217 }
9218 case XML_NAMESPACE_DECL:
9219 if (cur->type == XML_NAMESPACE_DECL) {
9220 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009221
Daniel Veillardf06307e2001-07-03 10:35:50 +00009222 if ((ns->prefix != NULL) && (name != NULL)
9223 && (xmlStrEqual(ns->prefix, name))) {
9224#ifdef DEBUG_STEP
9225 n++;
9226#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009227 xmlXPathNodeSetAddNs(list,
9228 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009229 }
9230 }
9231 break;
9232 default:
9233 break;
9234 }
9235 break;
9236 break;
9237 }
9238 } while (cur != NULL);
9239
9240 /*
9241 * If there is some predicate filtering do it now
9242 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009243 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009244 xmlXPathObjectPtr obj2;
9245
9246 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9247 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9248 CHECK_TYPE0(XPATH_NODESET);
9249 obj2 = valuePop(ctxt);
9250 list = obj2->nodesetval;
9251 obj2->nodesetval = NULL;
9252 xmlXPathFreeObject(obj2);
9253 }
9254 if (ret == NULL) {
9255 ret = list;
9256 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009257 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009258 xmlXPathFreeNodeSet(list);
9259 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009260 }
9261 ctxt->context->node = tmp;
9262#ifdef DEBUG_STEP
9263 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009264 "\nExamined %d nodes, found %d nodes at that step\n",
9265 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009266#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009267 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009268 if ((obj->boolval) && (obj->user != NULL)) {
9269 ctxt->value->boolval = 1;
9270 ctxt->value->user = obj->user;
9271 obj->user = NULL;
9272 obj->boolval = 0;
9273 }
9274 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009275 return(t);
9276}
9277
9278/**
9279 * xmlXPathNodeCollectAndTestNth:
9280 * @ctxt: the XPath Parser context
9281 * @op: the XPath precompiled step operation
9282 * @indx: the index to collect
9283 * @first: pointer to the first element in document order
9284 * @last: pointer to the last element in document order
9285 *
9286 * This is the function implementing a step: based on the current list
9287 * of nodes, it builds up a new list, looking at all nodes under that
9288 * axis and selecting them it also do the predicate filtering
9289 *
9290 * Pushes the new NodeSet resulting from the search.
9291 * Returns the number of node traversed
9292 */
9293static int
9294xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9295 xmlXPathStepOpPtr op, int indx,
9296 xmlNodePtr * first, xmlNodePtr * last)
9297{
William M. Brack78637da2003-07-31 14:47:38 +00009298 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9299 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9300 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009301 const xmlChar *prefix = op->value4;
9302 const xmlChar *name = op->value5;
9303 const xmlChar *URI = NULL;
9304 int n = 0, t = 0;
9305
9306 int i;
9307 xmlNodeSetPtr list;
9308 xmlXPathTraversalFunction next = NULL;
9309 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9310 xmlNodePtr cur = NULL;
9311 xmlXPathObjectPtr obj;
9312 xmlNodeSetPtr nodelist;
9313 xmlNodePtr tmp;
9314
9315 CHECK_TYPE0(XPATH_NODESET);
9316 obj = valuePop(ctxt);
9317 addNode = xmlXPathNodeSetAdd;
9318 if (prefix != NULL) {
9319 URI = xmlXPathNsLookup(ctxt->context, prefix);
9320 if (URI == NULL)
9321 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9322 }
9323#ifdef DEBUG_STEP_NTH
9324 xmlGenericError(xmlGenericErrorContext, "new step : ");
9325 if (first != NULL) {
9326 if (*first != NULL)
9327 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9328 (*first)->name);
9329 else
9330 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9331 }
9332 if (last != NULL) {
9333 if (*last != NULL)
9334 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9335 (*last)->name);
9336 else
9337 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9338 }
9339#endif
9340 switch (axis) {
9341 case AXIS_ANCESTOR:
9342#ifdef DEBUG_STEP_NTH
9343 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9344#endif
9345 first = NULL;
9346 next = xmlXPathNextAncestor;
9347 break;
9348 case AXIS_ANCESTOR_OR_SELF:
9349#ifdef DEBUG_STEP_NTH
9350 xmlGenericError(xmlGenericErrorContext,
9351 "axis 'ancestors-or-self' ");
9352#endif
9353 first = NULL;
9354 next = xmlXPathNextAncestorOrSelf;
9355 break;
9356 case AXIS_ATTRIBUTE:
9357#ifdef DEBUG_STEP_NTH
9358 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9359#endif
9360 first = NULL;
9361 last = NULL;
9362 next = xmlXPathNextAttribute;
9363 break;
9364 case AXIS_CHILD:
9365#ifdef DEBUG_STEP_NTH
9366 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9367#endif
9368 last = NULL;
9369 next = xmlXPathNextChild;
9370 break;
9371 case AXIS_DESCENDANT:
9372#ifdef DEBUG_STEP_NTH
9373 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9374#endif
9375 last = NULL;
9376 next = xmlXPathNextDescendant;
9377 break;
9378 case AXIS_DESCENDANT_OR_SELF:
9379#ifdef DEBUG_STEP_NTH
9380 xmlGenericError(xmlGenericErrorContext,
9381 "axis 'descendant-or-self' ");
9382#endif
9383 last = NULL;
9384 next = xmlXPathNextDescendantOrSelf;
9385 break;
9386 case AXIS_FOLLOWING:
9387#ifdef DEBUG_STEP_NTH
9388 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9389#endif
9390 last = NULL;
9391 next = xmlXPathNextFollowing;
9392 break;
9393 case AXIS_FOLLOWING_SIBLING:
9394#ifdef DEBUG_STEP_NTH
9395 xmlGenericError(xmlGenericErrorContext,
9396 "axis 'following-siblings' ");
9397#endif
9398 last = NULL;
9399 next = xmlXPathNextFollowingSibling;
9400 break;
9401 case AXIS_NAMESPACE:
9402#ifdef DEBUG_STEP_NTH
9403 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9404#endif
9405 last = NULL;
9406 first = NULL;
9407 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9408 break;
9409 case AXIS_PARENT:
9410#ifdef DEBUG_STEP_NTH
9411 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9412#endif
9413 first = NULL;
9414 next = xmlXPathNextParent;
9415 break;
9416 case AXIS_PRECEDING:
9417#ifdef DEBUG_STEP_NTH
9418 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9419#endif
9420 first = NULL;
9421 next = xmlXPathNextPrecedingInternal;
9422 break;
9423 case AXIS_PRECEDING_SIBLING:
9424#ifdef DEBUG_STEP_NTH
9425 xmlGenericError(xmlGenericErrorContext,
9426 "axis 'preceding-sibling' ");
9427#endif
9428 first = NULL;
9429 next = xmlXPathNextPrecedingSibling;
9430 break;
9431 case AXIS_SELF:
9432#ifdef DEBUG_STEP_NTH
9433 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9434#endif
9435 first = NULL;
9436 last = NULL;
9437 next = xmlXPathNextSelf;
9438 break;
9439 }
9440 if (next == NULL)
9441 return(0);
9442
9443 nodelist = obj->nodesetval;
9444 if (nodelist == NULL) {
9445 xmlXPathFreeObject(obj);
9446 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9447 return(0);
9448 }
9449 addNode = xmlXPathNodeSetAddUnique;
9450#ifdef DEBUG_STEP_NTH
9451 xmlGenericError(xmlGenericErrorContext,
9452 " context contains %d nodes\n", nodelist->nodeNr);
9453 switch (test) {
9454 case NODE_TEST_NONE:
9455 xmlGenericError(xmlGenericErrorContext,
9456 " searching for none !!!\n");
9457 break;
9458 case NODE_TEST_TYPE:
9459 xmlGenericError(xmlGenericErrorContext,
9460 " searching for type %d\n", type);
9461 break;
9462 case NODE_TEST_PI:
9463 xmlGenericError(xmlGenericErrorContext,
9464 " searching for PI !!!\n");
9465 break;
9466 case NODE_TEST_ALL:
9467 xmlGenericError(xmlGenericErrorContext,
9468 " searching for *\n");
9469 break;
9470 case NODE_TEST_NS:
9471 xmlGenericError(xmlGenericErrorContext,
9472 " searching for namespace %s\n",
9473 prefix);
9474 break;
9475 case NODE_TEST_NAME:
9476 xmlGenericError(xmlGenericErrorContext,
9477 " searching for name %s\n", name);
9478 if (prefix != NULL)
9479 xmlGenericError(xmlGenericErrorContext,
9480 " with namespace %s\n", prefix);
9481 break;
9482 }
9483 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9484#endif
9485 /*
9486 * 2.3 Node Tests
9487 * - For the attribute axis, the principal node type is attribute.
9488 * - For the namespace axis, the principal node type is namespace.
9489 * - For other axes, the principal node type is element.
9490 *
9491 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009492 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009493 * select all element children of the context node
9494 */
9495 tmp = ctxt->context->node;
9496 list = xmlXPathNodeSetCreate(NULL);
9497 for (i = 0; i < nodelist->nodeNr; i++) {
9498 ctxt->context->node = nodelist->nodeTab[i];
9499
9500 cur = NULL;
9501 n = 0;
9502 do {
9503 cur = next(ctxt, cur);
9504 if (cur == NULL)
9505 break;
9506 if ((first != NULL) && (*first == cur))
9507 break;
9508 if (((t % 256) == 0) &&
9509 (first != NULL) && (*first != NULL) &&
9510 (xmlXPathCmpNodes(*first, cur) >= 0))
9511 break;
9512 if ((last != NULL) && (*last == cur))
9513 break;
9514 if (((t % 256) == 0) &&
9515 (last != NULL) && (*last != NULL) &&
9516 (xmlXPathCmpNodes(cur, *last) >= 0))
9517 break;
9518 t++;
9519 switch (test) {
9520 case NODE_TEST_NONE:
9521 ctxt->context->node = tmp;
9522 STRANGE return(0);
9523 case NODE_TEST_TYPE:
9524 if ((cur->type == type) ||
9525 ((type == NODE_TYPE_NODE) &&
9526 ((cur->type == XML_DOCUMENT_NODE) ||
9527 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9528 (cur->type == XML_ELEMENT_NODE) ||
9529 (cur->type == XML_PI_NODE) ||
9530 (cur->type == XML_COMMENT_NODE) ||
9531 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009532 (cur->type == XML_TEXT_NODE))) ||
9533 ((type == NODE_TYPE_TEXT) &&
9534 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009535 n++;
9536 if (n == indx)
9537 addNode(list, cur);
9538 }
9539 break;
9540 case NODE_TEST_PI:
9541 if (cur->type == XML_PI_NODE) {
9542 if ((name != NULL) &&
9543 (!xmlStrEqual(name, cur->name)))
9544 break;
9545 n++;
9546 if (n == indx)
9547 addNode(list, cur);
9548 }
9549 break;
9550 case NODE_TEST_ALL:
9551 if (axis == AXIS_ATTRIBUTE) {
9552 if (cur->type == XML_ATTRIBUTE_NODE) {
9553 n++;
9554 if (n == indx)
9555 addNode(list, cur);
9556 }
9557 } else if (axis == AXIS_NAMESPACE) {
9558 if (cur->type == XML_NAMESPACE_DECL) {
9559 n++;
9560 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009561 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9562 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009563 }
9564 } else {
9565 if (cur->type == XML_ELEMENT_NODE) {
9566 if (prefix == NULL) {
9567 n++;
9568 if (n == indx)
9569 addNode(list, cur);
9570 } else if ((cur->ns != NULL) &&
9571 (xmlStrEqual(URI, cur->ns->href))) {
9572 n++;
9573 if (n == indx)
9574 addNode(list, cur);
9575 }
9576 }
9577 }
9578 break;
9579 case NODE_TEST_NS:{
9580 TODO;
9581 break;
9582 }
9583 case NODE_TEST_NAME:
9584 switch (cur->type) {
9585 case XML_ELEMENT_NODE:
9586 if (xmlStrEqual(name, cur->name)) {
9587 if (prefix == NULL) {
9588 if (cur->ns == NULL) {
9589 n++;
9590 if (n == indx)
9591 addNode(list, cur);
9592 }
9593 } else {
9594 if ((cur->ns != NULL) &&
9595 (xmlStrEqual(URI,
9596 cur->ns->href))) {
9597 n++;
9598 if (n == indx)
9599 addNode(list, cur);
9600 }
9601 }
9602 }
9603 break;
9604 case XML_ATTRIBUTE_NODE:{
9605 xmlAttrPtr attr = (xmlAttrPtr) cur;
9606
9607 if (xmlStrEqual(name, attr->name)) {
9608 if (prefix == NULL) {
9609 if ((attr->ns == NULL) ||
9610 (attr->ns->prefix == NULL)) {
9611 n++;
9612 if (n == indx)
9613 addNode(list, cur);
9614 }
9615 } else {
9616 if ((attr->ns != NULL) &&
9617 (xmlStrEqual(URI,
9618 attr->ns->
9619 href))) {
9620 n++;
9621 if (n == indx)
9622 addNode(list, cur);
9623 }
9624 }
9625 }
9626 break;
9627 }
9628 case XML_NAMESPACE_DECL:
9629 if (cur->type == XML_NAMESPACE_DECL) {
9630 xmlNsPtr ns = (xmlNsPtr) cur;
9631
9632 if ((ns->prefix != NULL) && (name != NULL)
9633 && (xmlStrEqual(ns->prefix, name))) {
9634 n++;
9635 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009636 xmlXPathNodeSetAddNs(list,
9637 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009638 }
9639 }
9640 break;
9641 default:
9642 break;
9643 }
9644 break;
9645 break;
9646 }
9647 } while (n < indx);
9648 }
9649 ctxt->context->node = tmp;
9650#ifdef DEBUG_STEP_NTH
9651 xmlGenericError(xmlGenericErrorContext,
9652 "\nExamined %d nodes, found %d nodes at that step\n",
9653 t, list->nodeNr);
9654#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009655 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009656 if ((obj->boolval) && (obj->user != NULL)) {
9657 ctxt->value->boolval = 1;
9658 ctxt->value->user = obj->user;
9659 obj->user = NULL;
9660 obj->boolval = 0;
9661 }
9662 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009663 return(t);
9664}
9665
9666/**
9667 * xmlXPathCompOpEvalFirst:
9668 * @ctxt: the XPath parser context with the compiled expression
9669 * @op: an XPath compiled operation
9670 * @first: the first elem found so far
9671 *
9672 * Evaluate the Precompiled XPath operation searching only the first
9673 * element in document order
9674 *
9675 * Returns the number of examined objects.
9676 */
9677static int
9678xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9679 xmlXPathStepOpPtr op, xmlNodePtr * first)
9680{
9681 int total = 0, cur;
9682 xmlXPathCompExprPtr comp;
9683 xmlXPathObjectPtr arg1, arg2;
9684
Daniel Veillard556c6682001-10-06 09:59:51 +00009685 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009686 comp = ctxt->comp;
9687 switch (op->op) {
9688 case XPATH_OP_END:
9689 return (0);
9690 case XPATH_OP_UNION:
9691 total =
9692 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9693 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009694 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009695 if ((ctxt->value != NULL)
9696 && (ctxt->value->type == XPATH_NODESET)
9697 && (ctxt->value->nodesetval != NULL)
9698 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9699 /*
9700 * limit tree traversing to first node in the result
9701 */
9702 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9703 *first = ctxt->value->nodesetval->nodeTab[0];
9704 }
9705 cur =
9706 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9707 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009708 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009709 CHECK_TYPE0(XPATH_NODESET);
9710 arg2 = valuePop(ctxt);
9711
9712 CHECK_TYPE0(XPATH_NODESET);
9713 arg1 = valuePop(ctxt);
9714
9715 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9716 arg2->nodesetval);
9717 valuePush(ctxt, arg1);
9718 xmlXPathFreeObject(arg2);
9719 /* optimizer */
9720 if (total > cur)
9721 xmlXPathCompSwap(op);
9722 return (total + cur);
9723 case XPATH_OP_ROOT:
9724 xmlXPathRoot(ctxt);
9725 return (0);
9726 case XPATH_OP_NODE:
9727 if (op->ch1 != -1)
9728 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009729 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009730 if (op->ch2 != -1)
9731 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009732 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009733 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9734 return (total);
9735 case XPATH_OP_RESET:
9736 if (op->ch1 != -1)
9737 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009738 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009739 if (op->ch2 != -1)
9740 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009741 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009742 ctxt->context->node = NULL;
9743 return (total);
9744 case XPATH_OP_COLLECT:{
9745 if (op->ch1 == -1)
9746 return (total);
9747
9748 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009749 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009750
9751 /*
9752 * Optimization for [n] selection where n is a number
9753 */
9754 if ((op->ch2 != -1) &&
9755 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9756 (comp->steps[op->ch2].ch1 == -1) &&
9757 (comp->steps[op->ch2].ch2 != -1) &&
9758 (comp->steps[comp->steps[op->ch2].ch2].op ==
9759 XPATH_OP_VALUE)) {
9760 xmlXPathObjectPtr val;
9761
9762 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9763 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9764 int indx = (int) val->floatval;
9765
9766 if (val->floatval == (float) indx) {
9767 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9768 first, NULL);
9769 return (total);
9770 }
9771 }
9772 }
9773 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9774 return (total);
9775 }
9776 case XPATH_OP_VALUE:
9777 valuePush(ctxt,
9778 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9779 return (0);
9780 case XPATH_OP_SORT:
9781 if (op->ch1 != -1)
9782 total +=
9783 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9784 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009785 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009786 if ((ctxt->value != NULL)
9787 && (ctxt->value->type == XPATH_NODESET)
9788 && (ctxt->value->nodesetval != NULL))
9789 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9790 return (total);
9791 default:
9792 return (xmlXPathCompOpEval(ctxt, op));
9793 }
9794}
9795
9796/**
9797 * xmlXPathCompOpEvalLast:
9798 * @ctxt: the XPath parser context with the compiled expression
9799 * @op: an XPath compiled operation
9800 * @last: the last elem found so far
9801 *
9802 * Evaluate the Precompiled XPath operation searching only the last
9803 * element in document order
9804 *
9805 * Returns the number of node traversed
9806 */
9807static int
9808xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9809 xmlNodePtr * last)
9810{
9811 int total = 0, cur;
9812 xmlXPathCompExprPtr comp;
9813 xmlXPathObjectPtr arg1, arg2;
9814
Daniel Veillard556c6682001-10-06 09:59:51 +00009815 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009816 comp = ctxt->comp;
9817 switch (op->op) {
9818 case XPATH_OP_END:
9819 return (0);
9820 case XPATH_OP_UNION:
9821 total =
9822 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009823 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009824 if ((ctxt->value != NULL)
9825 && (ctxt->value->type == XPATH_NODESET)
9826 && (ctxt->value->nodesetval != NULL)
9827 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9828 /*
9829 * limit tree traversing to first node in the result
9830 */
9831 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9832 *last =
9833 ctxt->value->nodesetval->nodeTab[ctxt->value->
9834 nodesetval->nodeNr -
9835 1];
9836 }
9837 cur =
9838 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009839 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009840 if ((ctxt->value != NULL)
9841 && (ctxt->value->type == XPATH_NODESET)
9842 && (ctxt->value->nodesetval != NULL)
9843 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9844 }
9845 CHECK_TYPE0(XPATH_NODESET);
9846 arg2 = valuePop(ctxt);
9847
9848 CHECK_TYPE0(XPATH_NODESET);
9849 arg1 = valuePop(ctxt);
9850
9851 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9852 arg2->nodesetval);
9853 valuePush(ctxt, arg1);
9854 xmlXPathFreeObject(arg2);
9855 /* optimizer */
9856 if (total > cur)
9857 xmlXPathCompSwap(op);
9858 return (total + cur);
9859 case XPATH_OP_ROOT:
9860 xmlXPathRoot(ctxt);
9861 return (0);
9862 case XPATH_OP_NODE:
9863 if (op->ch1 != -1)
9864 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009865 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009866 if (op->ch2 != -1)
9867 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009868 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009869 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9870 return (total);
9871 case XPATH_OP_RESET:
9872 if (op->ch1 != -1)
9873 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009874 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009875 if (op->ch2 != -1)
9876 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009877 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009878 ctxt->context->node = NULL;
9879 return (total);
9880 case XPATH_OP_COLLECT:{
9881 if (op->ch1 == -1)
9882 return (0);
9883
9884 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009885 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009886
9887 /*
9888 * Optimization for [n] selection where n is a number
9889 */
9890 if ((op->ch2 != -1) &&
9891 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9892 (comp->steps[op->ch2].ch1 == -1) &&
9893 (comp->steps[op->ch2].ch2 != -1) &&
9894 (comp->steps[comp->steps[op->ch2].ch2].op ==
9895 XPATH_OP_VALUE)) {
9896 xmlXPathObjectPtr val;
9897
9898 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9899 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9900 int indx = (int) val->floatval;
9901
9902 if (val->floatval == (float) indx) {
9903 total +=
9904 xmlXPathNodeCollectAndTestNth(ctxt, op,
9905 indx, NULL,
9906 last);
9907 return (total);
9908 }
9909 }
9910 }
9911 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9912 return (total);
9913 }
9914 case XPATH_OP_VALUE:
9915 valuePush(ctxt,
9916 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9917 return (0);
9918 case XPATH_OP_SORT:
9919 if (op->ch1 != -1)
9920 total +=
9921 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9922 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009923 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009924 if ((ctxt->value != NULL)
9925 && (ctxt->value->type == XPATH_NODESET)
9926 && (ctxt->value->nodesetval != NULL))
9927 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9928 return (total);
9929 default:
9930 return (xmlXPathCompOpEval(ctxt, op));
9931 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009932}
9933
Owen Taylor3473f882001-02-23 17:55:21 +00009934/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009935 * xmlXPathCompOpEval:
9936 * @ctxt: the XPath parser context with the compiled expression
9937 * @op: an XPath compiled operation
9938 *
9939 * Evaluate the Precompiled XPath operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009940 * Returns the number of node traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009941 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009942static int
9943xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9944{
9945 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009946 int equal, ret;
9947 xmlXPathCompExprPtr comp;
9948 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009949 xmlNodePtr bak;
9950 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009951 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009952 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009953
Daniel Veillard556c6682001-10-06 09:59:51 +00009954 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009955 comp = ctxt->comp;
9956 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009957 case XPATH_OP_END:
9958 return (0);
9959 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009960 bakd = ctxt->context->doc;
9961 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009962 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009963 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009964 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009965 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009966 xmlXPathBooleanFunction(ctxt, 1);
9967 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9968 return (total);
9969 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009970 ctxt->context->doc = bakd;
9971 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009972 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009973 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009974 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009975 if (ctxt->error) {
9976 xmlXPathFreeObject(arg2);
9977 return(0);
9978 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009979 xmlXPathBooleanFunction(ctxt, 1);
9980 arg1 = valuePop(ctxt);
9981 arg1->boolval &= arg2->boolval;
9982 valuePush(ctxt, arg1);
9983 xmlXPathFreeObject(arg2);
9984 return (total);
9985 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009986 bakd = ctxt->context->doc;
9987 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009988 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009989 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009990 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009991 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009992 xmlXPathBooleanFunction(ctxt, 1);
9993 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9994 return (total);
9995 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009996 ctxt->context->doc = bakd;
9997 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +00009998 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +00009999 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010000 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010001 if (ctxt->error) {
10002 xmlXPathFreeObject(arg2);
10003 return(0);
10004 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010005 xmlXPathBooleanFunction(ctxt, 1);
10006 arg1 = valuePop(ctxt);
10007 arg1->boolval |= arg2->boolval;
10008 valuePush(ctxt, arg1);
10009 xmlXPathFreeObject(arg2);
10010 return (total);
10011 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010012 bakd = ctxt->context->doc;
10013 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010014 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010015 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010016 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010017 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010018 ctxt->context->doc = bakd;
10019 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010020 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010021 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010022 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010023 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010024 if (op->value)
10025 equal = xmlXPathEqualValues(ctxt);
10026 else
10027 equal = xmlXPathNotEqualValues(ctxt);
10028 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010029 return (total);
10030 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010031 bakd = ctxt->context->doc;
10032 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010033 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010034 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010035 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010036 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010037 ctxt->context->doc = bakd;
10038 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010039 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010040 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010041 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010042 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010043 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10044 valuePush(ctxt, xmlXPathNewBoolean(ret));
10045 return (total);
10046 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010047 bakd = ctxt->context->doc;
10048 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010049 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010050 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010051 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010052 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010053 if (op->ch2 != -1) {
10054 ctxt->context->doc = bakd;
10055 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010056 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010057 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010058 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010059 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010060 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010061 if (op->value == 0)
10062 xmlXPathSubValues(ctxt);
10063 else if (op->value == 1)
10064 xmlXPathAddValues(ctxt);
10065 else if (op->value == 2)
10066 xmlXPathValueFlipSign(ctxt);
10067 else if (op->value == 3) {
10068 CAST_TO_NUMBER;
10069 CHECK_TYPE0(XPATH_NUMBER);
10070 }
10071 return (total);
10072 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010073 bakd = ctxt->context->doc;
10074 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010075 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010076 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010077 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010078 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010079 ctxt->context->doc = bakd;
10080 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010081 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010082 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010083 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010084 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010085 if (op->value == 0)
10086 xmlXPathMultValues(ctxt);
10087 else if (op->value == 1)
10088 xmlXPathDivValues(ctxt);
10089 else if (op->value == 2)
10090 xmlXPathModValues(ctxt);
10091 return (total);
10092 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010093 bakd = ctxt->context->doc;
10094 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010095 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010096 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010097 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010098 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010099 ctxt->context->doc = bakd;
10100 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010101 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010102 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010103 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010104 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010105 CHECK_TYPE0(XPATH_NODESET);
10106 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010107
Daniel Veillardf06307e2001-07-03 10:35:50 +000010108 CHECK_TYPE0(XPATH_NODESET);
10109 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010110
Daniel Veillardf06307e2001-07-03 10:35:50 +000010111 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10112 arg2->nodesetval);
10113 valuePush(ctxt, arg1);
10114 xmlXPathFreeObject(arg2);
10115 return (total);
10116 case XPATH_OP_ROOT:
10117 xmlXPathRoot(ctxt);
10118 return (total);
10119 case XPATH_OP_NODE:
10120 if (op->ch1 != -1)
10121 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010122 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010123 if (op->ch2 != -1)
10124 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010125 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010126 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10127 return (total);
10128 case XPATH_OP_RESET:
10129 if (op->ch1 != -1)
10130 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010131 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010132 if (op->ch2 != -1)
10133 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010134 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010135 ctxt->context->node = NULL;
10136 return (total);
10137 case XPATH_OP_COLLECT:{
10138 if (op->ch1 == -1)
10139 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010140
Daniel Veillardf06307e2001-07-03 10:35:50 +000010141 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010142 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010143
Daniel Veillardf06307e2001-07-03 10:35:50 +000010144 /*
10145 * Optimization for [n] selection where n is a number
10146 */
10147 if ((op->ch2 != -1) &&
10148 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10149 (comp->steps[op->ch2].ch1 == -1) &&
10150 (comp->steps[op->ch2].ch2 != -1) &&
10151 (comp->steps[comp->steps[op->ch2].ch2].op ==
10152 XPATH_OP_VALUE)) {
10153 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010154
Daniel Veillardf06307e2001-07-03 10:35:50 +000010155 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10156 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10157 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010158
Daniel Veillardf06307e2001-07-03 10:35:50 +000010159 if (val->floatval == (float) indx) {
10160 total +=
10161 xmlXPathNodeCollectAndTestNth(ctxt, op,
10162 indx, NULL,
10163 NULL);
10164 return (total);
10165 }
10166 }
10167 }
10168 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10169 return (total);
10170 }
10171 case XPATH_OP_VALUE:
10172 valuePush(ctxt,
10173 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10174 return (total);
10175 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010176 xmlXPathObjectPtr val;
10177
Daniel Veillardf06307e2001-07-03 10:35:50 +000010178 if (op->ch1 != -1)
10179 total +=
10180 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010181 if (op->value5 == NULL) {
10182 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10183 if (val == NULL) {
10184 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10185 return(0);
10186 }
10187 valuePush(ctxt, val);
10188 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010189 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010190
Daniel Veillardf06307e2001-07-03 10:35:50 +000010191 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10192 if (URI == NULL) {
10193 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010194 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010195 op->value4, op->value5);
10196 return (total);
10197 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010198 val = xmlXPathVariableLookupNS(ctxt->context,
10199 op->value4, URI);
10200 if (val == NULL) {
10201 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10202 return(0);
10203 }
10204 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010205 }
10206 return (total);
10207 }
10208 case XPATH_OP_FUNCTION:{
10209 xmlXPathFunction func;
10210 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010211 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010212
10213 if (op->ch1 != -1)
10214 total +=
10215 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010216 if (ctxt->valueNr < op->value) {
10217 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010218 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010219 ctxt->error = XPATH_INVALID_OPERAND;
10220 return (total);
10221 }
10222 for (i = 0; i < op->value; i++)
10223 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10224 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010225 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010226 ctxt->error = XPATH_INVALID_OPERAND;
10227 return (total);
10228 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010229 if (op->cache != NULL)
10230 func = (xmlXPathFunction) op->cache;
10231 else {
10232 const xmlChar *URI = NULL;
10233
10234 if (op->value5 == NULL)
10235 func =
10236 xmlXPathFunctionLookup(ctxt->context,
10237 op->value4);
10238 else {
10239 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10240 if (URI == NULL) {
10241 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010242 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010243 op->value4, op->value5);
10244 return (total);
10245 }
10246 func = xmlXPathFunctionLookupNS(ctxt->context,
10247 op->value4, URI);
10248 }
10249 if (func == NULL) {
10250 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010251 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010252 op->value4);
10253 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010254 }
10255 op->cache = (void *) func;
10256 op->cacheURI = (void *) URI;
10257 }
10258 oldFunc = ctxt->context->function;
10259 oldFuncURI = ctxt->context->functionURI;
10260 ctxt->context->function = op->value4;
10261 ctxt->context->functionURI = op->cacheURI;
10262 func(ctxt, op->value);
10263 ctxt->context->function = oldFunc;
10264 ctxt->context->functionURI = oldFuncURI;
10265 return (total);
10266 }
10267 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010268 bakd = ctxt->context->doc;
10269 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010270 if (op->ch1 != -1)
10271 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010272 ctxt->context->doc = bakd;
10273 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010274 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010275 if (op->ch2 != -1)
10276 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010277 ctxt->context->doc = bakd;
10278 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010279 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010280 return (total);
10281 case XPATH_OP_PREDICATE:
10282 case XPATH_OP_FILTER:{
10283 xmlXPathObjectPtr res;
10284 xmlXPathObjectPtr obj, tmp;
10285 xmlNodeSetPtr newset = NULL;
10286 xmlNodeSetPtr oldset;
10287 xmlNodePtr oldnode;
10288 int i;
10289
10290 /*
10291 * Optimization for ()[1] selection i.e. the first elem
10292 */
10293 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10294 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10295 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10296 xmlXPathObjectPtr val;
10297
10298 val = comp->steps[op->ch2].value4;
10299 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10300 (val->floatval == 1.0)) {
10301 xmlNodePtr first = NULL;
10302
10303 total +=
10304 xmlXPathCompOpEvalFirst(ctxt,
10305 &comp->steps[op->ch1],
10306 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010307 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010308 /*
10309 * The nodeset should be in document order,
10310 * Keep only the first value
10311 */
10312 if ((ctxt->value != NULL) &&
10313 (ctxt->value->type == XPATH_NODESET) &&
10314 (ctxt->value->nodesetval != NULL) &&
10315 (ctxt->value->nodesetval->nodeNr > 1))
10316 ctxt->value->nodesetval->nodeNr = 1;
10317 return (total);
10318 }
10319 }
10320 /*
10321 * Optimization for ()[last()] selection i.e. the last elem
10322 */
10323 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10324 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10325 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10326 int f = comp->steps[op->ch2].ch1;
10327
10328 if ((f != -1) &&
10329 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10330 (comp->steps[f].value5 == NULL) &&
10331 (comp->steps[f].value == 0) &&
10332 (comp->steps[f].value4 != NULL) &&
10333 (xmlStrEqual
10334 (comp->steps[f].value4, BAD_CAST "last"))) {
10335 xmlNodePtr last = NULL;
10336
10337 total +=
10338 xmlXPathCompOpEvalLast(ctxt,
10339 &comp->steps[op->ch1],
10340 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010341 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010342 /*
10343 * The nodeset should be in document order,
10344 * Keep only the last value
10345 */
10346 if ((ctxt->value != NULL) &&
10347 (ctxt->value->type == XPATH_NODESET) &&
10348 (ctxt->value->nodesetval != NULL) &&
10349 (ctxt->value->nodesetval->nodeTab != NULL) &&
10350 (ctxt->value->nodesetval->nodeNr > 1)) {
10351 ctxt->value->nodesetval->nodeTab[0] =
10352 ctxt->value->nodesetval->nodeTab[ctxt->
10353 value->
10354 nodesetval->
10355 nodeNr -
10356 1];
10357 ctxt->value->nodesetval->nodeNr = 1;
10358 }
10359 return (total);
10360 }
10361 }
10362
10363 if (op->ch1 != -1)
10364 total +=
10365 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010366 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010367 if (op->ch2 == -1)
10368 return (total);
10369 if (ctxt->value == NULL)
10370 return (total);
10371
10372 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010373
10374#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010375 /*
10376 * Hum are we filtering the result of an XPointer expression
10377 */
10378 if (ctxt->value->type == XPATH_LOCATIONSET) {
10379 xmlLocationSetPtr newlocset = NULL;
10380 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010381
Daniel Veillardf06307e2001-07-03 10:35:50 +000010382 /*
10383 * Extract the old locset, and then evaluate the result of the
10384 * expression for all the element in the locset. use it to grow
10385 * up a new locset.
10386 */
10387 CHECK_TYPE0(XPATH_LOCATIONSET);
10388 obj = valuePop(ctxt);
10389 oldlocset = obj->user;
10390 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010391
Daniel Veillardf06307e2001-07-03 10:35:50 +000010392 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10393 ctxt->context->contextSize = 0;
10394 ctxt->context->proximityPosition = 0;
10395 if (op->ch2 != -1)
10396 total +=
10397 xmlXPathCompOpEval(ctxt,
10398 &comp->steps[op->ch2]);
10399 res = valuePop(ctxt);
10400 if (res != NULL)
10401 xmlXPathFreeObject(res);
10402 valuePush(ctxt, obj);
10403 CHECK_ERROR0;
10404 return (total);
10405 }
10406 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010407
Daniel Veillardf06307e2001-07-03 10:35:50 +000010408 for (i = 0; i < oldlocset->locNr; i++) {
10409 /*
10410 * Run the evaluation with a node list made of a
10411 * single item in the nodelocset.
10412 */
10413 ctxt->context->node = oldlocset->locTab[i]->user;
10414 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10415 valuePush(ctxt, tmp);
10416 ctxt->context->contextSize = oldlocset->locNr;
10417 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010418
Daniel Veillardf06307e2001-07-03 10:35:50 +000010419 if (op->ch2 != -1)
10420 total +=
10421 xmlXPathCompOpEval(ctxt,
10422 &comp->steps[op->ch2]);
10423 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010424
Daniel Veillardf06307e2001-07-03 10:35:50 +000010425 /*
10426 * The result of the evaluation need to be tested to
10427 * decided whether the filter succeeded or not
10428 */
10429 res = valuePop(ctxt);
10430 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10431 xmlXPtrLocationSetAdd(newlocset,
10432 xmlXPathObjectCopy
10433 (oldlocset->locTab[i]));
10434 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010435
Daniel Veillardf06307e2001-07-03 10:35:50 +000010436 /*
10437 * Cleanup
10438 */
10439 if (res != NULL)
10440 xmlXPathFreeObject(res);
10441 if (ctxt->value == tmp) {
10442 res = valuePop(ctxt);
10443 xmlXPathFreeObject(res);
10444 }
10445
10446 ctxt->context->node = NULL;
10447 }
10448
10449 /*
10450 * The result is used as the new evaluation locset.
10451 */
10452 xmlXPathFreeObject(obj);
10453 ctxt->context->node = NULL;
10454 ctxt->context->contextSize = -1;
10455 ctxt->context->proximityPosition = -1;
10456 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10457 ctxt->context->node = oldnode;
10458 return (total);
10459 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010460#endif /* LIBXML_XPTR_ENABLED */
10461
Daniel Veillardf06307e2001-07-03 10:35:50 +000010462 /*
10463 * Extract the old set, and then evaluate the result of the
10464 * expression for all the element in the set. use it to grow
10465 * up a new set.
10466 */
10467 CHECK_TYPE0(XPATH_NODESET);
10468 obj = valuePop(ctxt);
10469 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010470
Daniel Veillardf06307e2001-07-03 10:35:50 +000010471 oldnode = ctxt->context->node;
10472 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010473
Daniel Veillardf06307e2001-07-03 10:35:50 +000010474 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10475 ctxt->context->contextSize = 0;
10476 ctxt->context->proximityPosition = 0;
10477 if (op->ch2 != -1)
10478 total +=
10479 xmlXPathCompOpEval(ctxt,
10480 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010481 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010482 res = valuePop(ctxt);
10483 if (res != NULL)
10484 xmlXPathFreeObject(res);
10485 valuePush(ctxt, obj);
10486 ctxt->context->node = oldnode;
10487 CHECK_ERROR0;
10488 } else {
10489 /*
10490 * Initialize the new set.
10491 */
10492 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010493
Daniel Veillardf06307e2001-07-03 10:35:50 +000010494 for (i = 0; i < oldset->nodeNr; i++) {
10495 /*
10496 * Run the evaluation with a node list made of
10497 * a single item in the nodeset.
10498 */
10499 ctxt->context->node = oldset->nodeTab[i];
10500 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10501 valuePush(ctxt, tmp);
10502 ctxt->context->contextSize = oldset->nodeNr;
10503 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010504
Daniel Veillardf06307e2001-07-03 10:35:50 +000010505 if (op->ch2 != -1)
10506 total +=
10507 xmlXPathCompOpEval(ctxt,
10508 &comp->steps[op->ch2]);
10509 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010510
Daniel Veillardf06307e2001-07-03 10:35:50 +000010511 /*
10512 * The result of the evaluation need to be tested to
10513 * decided whether the filter succeeded or not
10514 */
10515 res = valuePop(ctxt);
10516 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10517 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10518 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010519
Daniel Veillardf06307e2001-07-03 10:35:50 +000010520 /*
10521 * Cleanup
10522 */
10523 if (res != NULL)
10524 xmlXPathFreeObject(res);
10525 if (ctxt->value == tmp) {
10526 res = valuePop(ctxt);
10527 xmlXPathFreeObject(res);
10528 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010529
Daniel Veillardf06307e2001-07-03 10:35:50 +000010530 ctxt->context->node = NULL;
10531 }
10532
10533 /*
10534 * The result is used as the new evaluation set.
10535 */
10536 xmlXPathFreeObject(obj);
10537 ctxt->context->node = NULL;
10538 ctxt->context->contextSize = -1;
10539 ctxt->context->proximityPosition = -1;
10540 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10541 }
10542 ctxt->context->node = oldnode;
10543 return (total);
10544 }
10545 case XPATH_OP_SORT:
10546 if (op->ch1 != -1)
10547 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010548 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010549 if ((ctxt->value != NULL) &&
10550 (ctxt->value->type == XPATH_NODESET) &&
10551 (ctxt->value->nodesetval != NULL))
10552 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10553 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010554#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010555 case XPATH_OP_RANGETO:{
10556 xmlXPathObjectPtr range;
10557 xmlXPathObjectPtr res, obj;
10558 xmlXPathObjectPtr tmp;
10559 xmlLocationSetPtr newset = NULL;
10560 xmlNodeSetPtr oldset;
10561 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010562
Daniel Veillardf06307e2001-07-03 10:35:50 +000010563 if (op->ch1 != -1)
10564 total +=
10565 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10566 if (op->ch2 == -1)
10567 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010568
Daniel Veillardf06307e2001-07-03 10:35:50 +000010569 CHECK_TYPE0(XPATH_NODESET);
10570 obj = valuePop(ctxt);
10571 oldset = obj->nodesetval;
10572 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010573
Daniel Veillardf06307e2001-07-03 10:35:50 +000010574 newset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010575
Daniel Veillardf06307e2001-07-03 10:35:50 +000010576 if (oldset != NULL) {
10577 for (i = 0; i < oldset->nodeNr; i++) {
10578 /*
10579 * Run the evaluation with a node list made of a single item
10580 * in the nodeset.
10581 */
10582 ctxt->context->node = oldset->nodeTab[i];
10583 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10584 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010585
Daniel Veillardf06307e2001-07-03 10:35:50 +000010586 if (op->ch2 != -1)
10587 total +=
10588 xmlXPathCompOpEval(ctxt,
10589 &comp->steps[op->ch2]);
10590 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010591
Daniel Veillardf06307e2001-07-03 10:35:50 +000010592 /*
10593 * The result of the evaluation need to be tested to
10594 * decided whether the filter succeeded or not
10595 */
10596 res = valuePop(ctxt);
10597 range =
10598 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10599 res);
10600 if (range != NULL) {
10601 xmlXPtrLocationSetAdd(newset, range);
10602 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010603
Daniel Veillardf06307e2001-07-03 10:35:50 +000010604 /*
10605 * Cleanup
10606 */
10607 if (res != NULL)
10608 xmlXPathFreeObject(res);
10609 if (ctxt->value == tmp) {
10610 res = valuePop(ctxt);
10611 xmlXPathFreeObject(res);
10612 }
10613
10614 ctxt->context->node = NULL;
10615 }
10616 }
10617
10618 /*
10619 * The result is used as the new evaluation set.
10620 */
10621 xmlXPathFreeObject(obj);
10622 ctxt->context->node = NULL;
10623 ctxt->context->contextSize = -1;
10624 ctxt->context->proximityPosition = -1;
10625 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10626 return (total);
10627 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010628#endif /* LIBXML_XPTR_ENABLED */
10629 }
10630 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010631 "XPath: unknown precompiled operation %d\n", op->op);
10632 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010633}
10634
10635/**
10636 * xmlXPathRunEval:
10637 * @ctxt: the XPath parser context with the compiled expression
10638 *
10639 * Evaluate the Precompiled XPath expression in the given context.
10640 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010641static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010642xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10643 xmlXPathCompExprPtr comp;
10644
10645 if ((ctxt == NULL) || (ctxt->comp == NULL))
10646 return;
10647
10648 if (ctxt->valueTab == NULL) {
10649 /* Allocate the value stack */
10650 ctxt->valueTab = (xmlXPathObjectPtr *)
10651 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10652 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010653 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010654 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010655 }
10656 ctxt->valueNr = 0;
10657 ctxt->valueMax = 10;
10658 ctxt->value = NULL;
10659 }
10660 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010661 if(comp->last < 0) {
10662 xmlGenericError(xmlGenericErrorContext,
10663 "xmlXPathRunEval: last is less than zero\n");
10664 return;
10665 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010666 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10667}
10668
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010669/************************************************************************
10670 * *
10671 * Public interfaces *
10672 * *
10673 ************************************************************************/
10674
10675/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010676 * xmlXPathEvalPredicate:
10677 * @ctxt: the XPath context
10678 * @res: the Predicate Expression evaluation result
10679 *
10680 * Evaluate a predicate result for the current node.
10681 * A PredicateExpr is evaluated by evaluating the Expr and converting
10682 * the result to a boolean. If the result is a number, the result will
10683 * be converted to true if the number is equal to the position of the
10684 * context node in the context node list (as returned by the position
10685 * function) and will be converted to false otherwise; if the result
10686 * is not a number, then the result will be converted as if by a call
10687 * to the boolean function.
10688 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010689 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010690 */
10691int
10692xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10693 if (res == NULL) return(0);
10694 switch (res->type) {
10695 case XPATH_BOOLEAN:
10696 return(res->boolval);
10697 case XPATH_NUMBER:
10698 return(res->floatval == ctxt->proximityPosition);
10699 case XPATH_NODESET:
10700 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010701 if (res->nodesetval == NULL)
10702 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010703 return(res->nodesetval->nodeNr != 0);
10704 case XPATH_STRING:
10705 return((res->stringval != NULL) &&
10706 (xmlStrlen(res->stringval) != 0));
10707 default:
10708 STRANGE
10709 }
10710 return(0);
10711}
10712
10713/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010714 * xmlXPathEvaluatePredicateResult:
10715 * @ctxt: the XPath Parser context
10716 * @res: the Predicate Expression evaluation result
10717 *
10718 * Evaluate a predicate result for the current node.
10719 * A PredicateExpr is evaluated by evaluating the Expr and converting
10720 * the result to a boolean. If the result is a number, the result will
10721 * be converted to true if the number is equal to the position of the
10722 * context node in the context node list (as returned by the position
10723 * function) and will be converted to false otherwise; if the result
10724 * is not a number, then the result will be converted as if by a call
10725 * to the boolean function.
10726 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010727 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010728 */
10729int
10730xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10731 xmlXPathObjectPtr res) {
10732 if (res == NULL) return(0);
10733 switch (res->type) {
10734 case XPATH_BOOLEAN:
10735 return(res->boolval);
10736 case XPATH_NUMBER:
10737 return(res->floatval == ctxt->context->proximityPosition);
10738 case XPATH_NODESET:
10739 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010740 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010741 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010742 return(res->nodesetval->nodeNr != 0);
10743 case XPATH_STRING:
10744 return((res->stringval != NULL) &&
10745 (xmlStrlen(res->stringval) != 0));
10746 default:
10747 STRANGE
10748 }
10749 return(0);
10750}
10751
10752/**
10753 * xmlXPathCompile:
10754 * @str: the XPath expression
10755 *
10756 * Compile an XPath expression
10757 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010758 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010759 * the caller has to free the object.
10760 */
10761xmlXPathCompExprPtr
10762xmlXPathCompile(const xmlChar *str) {
10763 xmlXPathParserContextPtr ctxt;
10764 xmlXPathCompExprPtr comp;
10765
10766 xmlXPathInit();
10767
10768 ctxt = xmlXPathNewParserContext(str, NULL);
10769 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010770
Daniel Veillard40af6492001-04-22 08:50:55 +000010771 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010772 /*
10773 * aleksey: in some cases this line prints *second* error message
10774 * (see bug #78858) and probably this should be fixed.
10775 * However, we are not sure that all error messages are printed
10776 * out in other places. It's not critical so we leave it as-is for now
10777 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010778 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10779 comp = NULL;
10780 } else {
10781 comp = ctxt->comp;
10782 ctxt->comp = NULL;
10783 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010784 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010785 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010786 comp->expr = xmlStrdup(str);
10787#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010788 comp->string = xmlStrdup(str);
10789 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010790#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010791 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010792 return(comp);
10793}
10794
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010795/**
10796 * xmlXPathCompiledEval:
10797 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010798 * @ctx: the XPath context
10799 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010800 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010801 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010802 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010803 * the caller has to free the object.
10804 */
10805xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010806xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010807 xmlXPathParserContextPtr ctxt;
10808 xmlXPathObjectPtr res, tmp, init = NULL;
10809 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010810#ifndef LIBXML_THREAD_ENABLED
10811 static int reentance = 0;
10812#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010813
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010814 if ((comp == NULL) || (ctx == NULL))
10815 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010816 xmlXPathInit();
10817
10818 CHECK_CONTEXT(ctx)
10819
Daniel Veillard81463942001-10-16 12:34:39 +000010820#ifndef LIBXML_THREAD_ENABLED
10821 reentance++;
10822 if (reentance > 1)
10823 xmlXPathDisableOptimizer = 1;
10824#endif
10825
Daniel Veillardf06307e2001-07-03 10:35:50 +000010826#ifdef DEBUG_EVAL_COUNTS
10827 comp->nb++;
10828 if ((comp->string != NULL) && (comp->nb > 100)) {
10829 fprintf(stderr, "100 x %s\n", comp->string);
10830 comp->nb = 0;
10831 }
10832#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010833 ctxt = xmlXPathCompParserContext(comp, ctx);
10834 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010835
10836 if (ctxt->value == NULL) {
10837 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010838 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010839 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010840 } else {
10841 res = valuePop(ctxt);
10842 }
10843
Daniel Veillardf06307e2001-07-03 10:35:50 +000010844
Owen Taylor3473f882001-02-23 17:55:21 +000010845 do {
10846 tmp = valuePop(ctxt);
10847 if (tmp != NULL) {
10848 if (tmp != init)
10849 stack++;
10850 xmlXPathFreeObject(tmp);
10851 }
10852 } while (tmp != NULL);
10853 if ((stack != 0) && (res != NULL)) {
10854 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010855 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010856 stack);
10857 }
10858 if (ctxt->error != XPATH_EXPRESSION_OK) {
10859 xmlXPathFreeObject(res);
10860 res = NULL;
10861 }
10862
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010863
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010864 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010865 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010866#ifndef LIBXML_THREAD_ENABLED
10867 reentance--;
10868#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010869 return(res);
10870}
10871
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010872/**
10873 * xmlXPathEvalExpr:
10874 * @ctxt: the XPath Parser context
10875 *
10876 * Parse and evaluate an XPath expression in the given context,
10877 * then push the result on the context stack
10878 */
10879void
10880xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10881 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010882 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010883 xmlXPathRunEval(ctxt);
10884}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010885
10886/**
10887 * xmlXPathEval:
10888 * @str: the XPath expression
10889 * @ctx: the XPath context
10890 *
10891 * Evaluate the XPath Location Path in the given context.
10892 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010893 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010894 * the caller has to free the object.
10895 */
10896xmlXPathObjectPtr
10897xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10898 xmlXPathParserContextPtr ctxt;
10899 xmlXPathObjectPtr res, tmp, init = NULL;
10900 int stack = 0;
10901
10902 xmlXPathInit();
10903
10904 CHECK_CONTEXT(ctx)
10905
10906 ctxt = xmlXPathNewParserContext(str, ctx);
10907 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010908
10909 if (ctxt->value == NULL) {
10910 xmlGenericError(xmlGenericErrorContext,
10911 "xmlXPathEval: evaluation failed\n");
10912 res = NULL;
10913 } else if (*ctxt->cur != 0) {
10914 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10915 res = NULL;
10916 } else {
10917 res = valuePop(ctxt);
10918 }
10919
10920 do {
10921 tmp = valuePop(ctxt);
10922 if (tmp != NULL) {
10923 if (tmp != init)
10924 stack++;
10925 xmlXPathFreeObject(tmp);
10926 }
10927 } while (tmp != NULL);
10928 if ((stack != 0) && (res != NULL)) {
10929 xmlGenericError(xmlGenericErrorContext,
10930 "xmlXPathEval: %d object left on the stack\n",
10931 stack);
10932 }
10933 if (ctxt->error != XPATH_EXPRESSION_OK) {
10934 xmlXPathFreeObject(res);
10935 res = NULL;
10936 }
10937
Owen Taylor3473f882001-02-23 17:55:21 +000010938 xmlXPathFreeParserContext(ctxt);
10939 return(res);
10940}
10941
10942/**
10943 * xmlXPathEvalExpression:
10944 * @str: the XPath expression
10945 * @ctxt: the XPath context
10946 *
10947 * Evaluate the XPath expression in the given context.
10948 *
10949 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10950 * the caller has to free the object.
10951 */
10952xmlXPathObjectPtr
10953xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10954 xmlXPathParserContextPtr pctxt;
10955 xmlXPathObjectPtr res, tmp;
10956 int stack = 0;
10957
10958 xmlXPathInit();
10959
10960 CHECK_CONTEXT(ctxt)
10961
10962 pctxt = xmlXPathNewParserContext(str, ctxt);
10963 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010964
10965 if (*pctxt->cur != 0) {
10966 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10967 res = NULL;
10968 } else {
10969 res = valuePop(pctxt);
10970 }
10971 do {
10972 tmp = valuePop(pctxt);
10973 if (tmp != NULL) {
10974 xmlXPathFreeObject(tmp);
10975 stack++;
10976 }
10977 } while (tmp != NULL);
10978 if ((stack != 0) && (res != NULL)) {
10979 xmlGenericError(xmlGenericErrorContext,
10980 "xmlXPathEvalExpression: %d object left on the stack\n",
10981 stack);
10982 }
10983 xmlXPathFreeParserContext(pctxt);
10984 return(res);
10985}
10986
Daniel Veillard42766c02002-08-22 20:52:17 +000010987/************************************************************************
10988 * *
10989 * Extra functions not pertaining to the XPath spec *
10990 * *
10991 ************************************************************************/
10992/**
10993 * xmlXPathEscapeUriFunction:
10994 * @ctxt: the XPath Parser context
10995 * @nargs: the number of arguments
10996 *
10997 * Implement the escape-uri() XPath function
10998 * string escape-uri(string $str, bool $escape-reserved)
10999 *
11000 * This function applies the URI escaping rules defined in section 2 of [RFC
11001 * 2396] to the string supplied as $uri-part, which typically represents all
11002 * or part of a URI. The effect of the function is to replace any special
11003 * character in the string by an escape sequence of the form %xx%yy...,
11004 * where xxyy... is the hexadecimal representation of the octets used to
11005 * represent the character in UTF-8.
11006 *
11007 * The set of characters that are escaped depends on the setting of the
11008 * boolean argument $escape-reserved.
11009 *
11010 * If $escape-reserved is true, all characters are escaped other than lower
11011 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11012 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11013 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11014 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11015 * A-F).
11016 *
11017 * If $escape-reserved is false, the behavior differs in that characters
11018 * referred to in [RFC 2396] as reserved characters are not escaped. These
11019 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11020 *
11021 * [RFC 2396] does not define whether escaped URIs should use lower case or
11022 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11023 * compared using string comparison functions, this function must always use
11024 * the upper-case letters A-F.
11025 *
11026 * Generally, $escape-reserved should be set to true when escaping a string
11027 * that is to form a single part of a URI, and to false when escaping an
11028 * entire URI or URI reference.
11029 *
11030 * In the case of non-ascii characters, the string is encoded according to
11031 * utf-8 and then converted according to RFC 2396.
11032 *
11033 * Examples
11034 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11035 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11036 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11037 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11038 *
11039 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011040static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011041xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11042 xmlXPathObjectPtr str;
11043 int escape_reserved;
11044 xmlBufferPtr target;
11045 xmlChar *cptr;
11046 xmlChar escape[4];
11047
11048 CHECK_ARITY(2);
11049
11050 escape_reserved = xmlXPathPopBoolean(ctxt);
11051
11052 CAST_TO_STRING;
11053 str = valuePop(ctxt);
11054
11055 target = xmlBufferCreate();
11056
11057 escape[0] = '%';
11058 escape[3] = 0;
11059
11060 if (target) {
11061 for (cptr = str->stringval; *cptr; cptr++) {
11062 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11063 (*cptr >= 'a' && *cptr <= 'z') ||
11064 (*cptr >= '0' && *cptr <= '9') ||
11065 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11066 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11067 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11068 (*cptr == '%' &&
11069 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11070 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11071 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11072 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11073 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11074 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11075 (!escape_reserved &&
11076 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11077 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11078 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11079 *cptr == ','))) {
11080 xmlBufferAdd(target, cptr, 1);
11081 } else {
11082 if ((*cptr >> 4) < 10)
11083 escape[1] = '0' + (*cptr >> 4);
11084 else
11085 escape[1] = 'A' - 10 + (*cptr >> 4);
11086 if ((*cptr & 0xF) < 10)
11087 escape[2] = '0' + (*cptr & 0xF);
11088 else
11089 escape[2] = 'A' - 10 + (*cptr & 0xF);
11090
11091 xmlBufferAdd(target, &escape[0], 3);
11092 }
11093 }
11094 }
11095 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11096 xmlBufferFree(target);
11097 xmlXPathFreeObject(str);
11098}
11099
Owen Taylor3473f882001-02-23 17:55:21 +000011100/**
11101 * xmlXPathRegisterAllFunctions:
11102 * @ctxt: the XPath context
11103 *
11104 * Registers all default XPath functions in this context
11105 */
11106void
11107xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11108{
11109 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11110 xmlXPathBooleanFunction);
11111 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11112 xmlXPathCeilingFunction);
11113 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11114 xmlXPathCountFunction);
11115 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11116 xmlXPathConcatFunction);
11117 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11118 xmlXPathContainsFunction);
11119 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11120 xmlXPathIdFunction);
11121 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11122 xmlXPathFalseFunction);
11123 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11124 xmlXPathFloorFunction);
11125 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11126 xmlXPathLastFunction);
11127 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11128 xmlXPathLangFunction);
11129 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11130 xmlXPathLocalNameFunction);
11131 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11132 xmlXPathNotFunction);
11133 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11134 xmlXPathNameFunction);
11135 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11136 xmlXPathNamespaceURIFunction);
11137 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11138 xmlXPathNormalizeFunction);
11139 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11140 xmlXPathNumberFunction);
11141 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11142 xmlXPathPositionFunction);
11143 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11144 xmlXPathRoundFunction);
11145 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11146 xmlXPathStringFunction);
11147 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11148 xmlXPathStringLengthFunction);
11149 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11150 xmlXPathStartsWithFunction);
11151 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11152 xmlXPathSubstringFunction);
11153 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11154 xmlXPathSubstringBeforeFunction);
11155 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11156 xmlXPathSubstringAfterFunction);
11157 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11158 xmlXPathSumFunction);
11159 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11160 xmlXPathTrueFunction);
11161 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11162 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011163
11164 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11165 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11166 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011167}
11168
11169#endif /* LIBXML_XPATH_ENABLED */