blob: 0fa53b80dd0965e65fa1e8e3788131fa2f240e56 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
Owen Taylor3473f882001-02-23 17:55:21 +000031#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000034#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000035#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#endif
Owen Taylor3473f882001-02-23 17:55:21 +000037
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000052#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000053#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000054
Daniel Veillardd96f6d32003-10-07 21:25:12 +000055#define TODO \
56 xmlGenericError(xmlGenericErrorContext, \
57 "Unimplemented block at %s:%d\n", \
58 __FILE__, __LINE__);
59
Daniel Veillard4432df22003-09-28 18:58:27 +000060#if defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000061/************************************************************************
62 * *
63 * Floating point stuff *
64 * *
65 ************************************************************************/
66
Daniel Veillardc0631a62001-09-20 13:56:06 +000067#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000068#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000069#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000070#include "trionan.c"
71
Owen Taylor3473f882001-02-23 17:55:21 +000072/*
Owen Taylor3473f882001-02-23 17:55:21 +000073 * The lack of portability of this section of the libc is annoying !
74 */
75double xmlXPathNAN = 0;
76double xmlXPathPINF = 1;
77double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000078double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000079static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000080
Owen Taylor3473f882001-02-23 17:55:21 +000081/**
82 * xmlXPathInit:
83 *
84 * Initialize the XPath environment
85 */
86void
87xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +000088 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +000089
Bjorn Reese45029602001-08-21 09:23:53 +000090 xmlXPathPINF = trio_pinf();
91 xmlXPathNINF = trio_ninf();
92 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +000093 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +000094
Daniel Veillard20ee8c02001-10-05 09:18:14 +000095 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000096}
97
Daniel Veillardcda96922001-08-21 10:56:31 +000098/**
99 * xmlXPathIsNaN:
100 * @val: a double value
101 *
102 * Provides a portable isnan() function to detect whether a double
103 * is a NotaNumber. Based on trio code
104 * http://sourceforge.net/projects/ctrio/
105 *
106 * Returns 1 if the value is a NaN, 0 otherwise
107 */
108int
109xmlXPathIsNaN(double val) {
110 return(trio_isnan(val));
111}
112
113/**
114 * xmlXPathIsInf:
115 * @val: a double value
116 *
117 * Provides a portable isinf() function to detect whether a double
118 * is a +Infinite or -Infinite. Based on trio code
119 * http://sourceforge.net/projects/ctrio/
120 *
121 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
122 */
123int
124xmlXPathIsInf(double val) {
125 return(trio_isinf(val));
126}
127
Daniel Veillard4432df22003-09-28 18:58:27 +0000128#endif /* SCHEMAS or XPATH */
129#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000130/**
131 * xmlXPathGetSign:
132 * @val: a double value
133 *
134 * Provides a portable function to detect the sign of a double
135 * Modified from trio code
136 * http://sourceforge.net/projects/ctrio/
137 *
138 * Returns 1 if the value is Negative, 0 if positive
139 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000140static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000141xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000142 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000143}
144
145
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000146/*
147 * TODO: when compatibility allows remove all "fake node libxslt" strings
148 * the test should just be name[0] = ' '
149 */
150/* #define DEBUG */
151/* #define DEBUG_STEP */
152/* #define DEBUG_STEP_NTH */
153/* #define DEBUG_EXPR */
154/* #define DEBUG_EVAL_COUNTS */
155
156static xmlNs xmlXPathXMLNamespaceStruct = {
157 NULL,
158 XML_NAMESPACE_DECL,
159 XML_XML_NAMESPACE,
160 BAD_CAST "xml",
161 NULL
162};
163static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
164#ifndef LIBXML_THREAD_ENABLED
165/*
166 * Optimizer is disabled only when threaded apps are detected while
167 * the library ain't compiled for thread safety.
168 */
169static int xmlXPathDisableOptimizer = 0;
170#endif
171
Owen Taylor3473f882001-02-23 17:55:21 +0000172/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000173 * *
174 * Error handling routines *
175 * *
176 ************************************************************************/
177
William M. Brack08171912003-12-29 02:52:11 +0000178/*
179 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
180 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000181static const char *xmlXPathErrorMessages[] = {
182 "Ok\n",
183 "Number encoding\n",
184 "Unfinished literal\n",
185 "Start of literal\n",
186 "Expected $ for variable reference\n",
187 "Undefined variable\n",
188 "Invalid predicate\n",
189 "Invalid expression\n",
190 "Missing closing curly brace\n",
191 "Unregistered function\n",
192 "Invalid operand\n",
193 "Invalid type\n",
194 "Invalid number of arguments\n",
195 "Invalid context size\n",
196 "Invalid context position\n",
197 "Memory allocation error\n",
198 "Syntax error\n",
199 "Resource error\n",
200 "Sub resource error\n",
201 "Undefined namespace prefix\n",
202 "Encoding error\n",
203 "Char out of XML range\n"
204};
205
206
207/**
208 * xmlXPathErrMemory:
209 * @ctxt: an XPath context
210 * @extra: extra informations
211 *
212 * Handle a redefinition of attribute error
213 */
214static void
215xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
216{
217 if (ctxt != NULL) {
218 if (extra) {
219 xmlChar buf[200];
220
221 xmlStrPrintf(buf, 200,
222 BAD_CAST "Memory allocation failed : %s\n",
223 extra);
224 ctxt->lastError.message = (char *) xmlStrdup(buf);
225 } else {
226 ctxt->lastError.message = (char *)
227 xmlStrdup(BAD_CAST "Memory allocation failed\n");
228 }
229 ctxt->lastError.domain = XML_FROM_XPATH;
230 ctxt->lastError.code = XML_ERR_NO_MEMORY;
231 if (ctxt->error != NULL)
232 ctxt->error(ctxt->userData, &ctxt->lastError);
233 } else {
234 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000235 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000236 NULL, NULL, XML_FROM_XPATH,
237 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
238 extra, NULL, NULL, 0, 0,
239 "Memory allocation failed : %s\n", extra);
240 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000241 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000242 NULL, NULL, XML_FROM_XPATH,
243 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
244 NULL, NULL, NULL, 0, 0,
245 "Memory allocation failed\n");
246 }
247}
248
249/**
250 * xmlXPathErrMemory:
251 * @ctxt: an XPath parser context
252 * @extra: extra informations
253 *
254 * Handle a redefinition of attribute error
255 */
256static void
257xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
258{
259 ctxt->error = XPATH_MEMORY_ERROR;
260 if (ctxt == NULL)
261 xmlXPathErrMemory(NULL, extra);
262 else
263 xmlXPathErrMemory(ctxt->context, extra);
264}
265
266/**
267 * xmlXPathErr:
268 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000269 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000270 *
271 * Handle a Relax NG Parsing error
272 */
273void
274xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
275{
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000276 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000277 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000278 NULL, NULL, XML_FROM_XPATH,
279 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
280 XML_ERR_ERROR, NULL, 0,
281 NULL, NULL, NULL, 0, 0,
282 xmlXPathErrorMessages[error]);
283 return;
284 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000285 ctxt->error = error;
286 if (ctxt->context == NULL) {
287 __xmlRaiseError(NULL, NULL, NULL,
288 NULL, NULL, XML_FROM_XPATH,
289 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
290 XML_ERR_ERROR, NULL, 0,
291 (const char *) ctxt->base, NULL, NULL,
292 ctxt->cur - ctxt->base, 0,
293 xmlXPathErrorMessages[error]);
294 return;
295 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000296 ctxt->context->lastError.domain = XML_FROM_XPATH;
297 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
298 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000299 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000300 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
301 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
302 ctxt->context->lastError.node = ctxt->context->debugNode;
303 if (ctxt->context->error != NULL) {
304 ctxt->context->error(ctxt->context->userData,
305 &ctxt->context->lastError);
306 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000307 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000308 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
309 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
310 XML_ERR_ERROR, NULL, 0,
311 (const char *) ctxt->base, NULL, NULL,
312 ctxt->cur - ctxt->base, 0,
313 xmlXPathErrorMessages[error]);
314 }
315
316}
317
318/**
319 * xmlXPatherror:
320 * @ctxt: the XPath Parser context
321 * @file: the file name
322 * @line: the line number
323 * @no: the error number
324 *
325 * Formats an error message.
326 */
327void
328xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
329 int line ATTRIBUTE_UNUSED, int no) {
330 xmlXPathErr(ctxt, no);
331}
332
333
334/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000335 * *
336 * Parser Types *
337 * *
338 ************************************************************************/
339
340/*
341 * Types are private:
342 */
343
344typedef enum {
345 XPATH_OP_END=0,
346 XPATH_OP_AND,
347 XPATH_OP_OR,
348 XPATH_OP_EQUAL,
349 XPATH_OP_CMP,
350 XPATH_OP_PLUS,
351 XPATH_OP_MULT,
352 XPATH_OP_UNION,
353 XPATH_OP_ROOT,
354 XPATH_OP_NODE,
355 XPATH_OP_RESET,
356 XPATH_OP_COLLECT,
357 XPATH_OP_VALUE,
358 XPATH_OP_VARIABLE,
359 XPATH_OP_FUNCTION,
360 XPATH_OP_ARG,
361 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000362 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000363 XPATH_OP_SORT
364#ifdef LIBXML_XPTR_ENABLED
365 ,XPATH_OP_RANGETO
366#endif
367} xmlXPathOp;
368
369typedef enum {
370 AXIS_ANCESTOR = 1,
371 AXIS_ANCESTOR_OR_SELF,
372 AXIS_ATTRIBUTE,
373 AXIS_CHILD,
374 AXIS_DESCENDANT,
375 AXIS_DESCENDANT_OR_SELF,
376 AXIS_FOLLOWING,
377 AXIS_FOLLOWING_SIBLING,
378 AXIS_NAMESPACE,
379 AXIS_PARENT,
380 AXIS_PRECEDING,
381 AXIS_PRECEDING_SIBLING,
382 AXIS_SELF
383} xmlXPathAxisVal;
384
385typedef enum {
386 NODE_TEST_NONE = 0,
387 NODE_TEST_TYPE = 1,
388 NODE_TEST_PI = 2,
389 NODE_TEST_ALL = 3,
390 NODE_TEST_NS = 4,
391 NODE_TEST_NAME = 5
392} xmlXPathTestVal;
393
394typedef enum {
395 NODE_TYPE_NODE = 0,
396 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
397 NODE_TYPE_TEXT = XML_TEXT_NODE,
398 NODE_TYPE_PI = XML_PI_NODE
399} xmlXPathTypeVal;
400
401
402typedef struct _xmlXPathStepOp xmlXPathStepOp;
403typedef xmlXPathStepOp *xmlXPathStepOpPtr;
404struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000405 xmlXPathOp op; /* The identifier of the operation */
406 int ch1; /* First child */
407 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000408 int value;
409 int value2;
410 int value3;
411 void *value4;
412 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000413 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000414 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000415};
416
417struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000418 int nbStep; /* Number of steps in this expression */
419 int maxStep; /* Maximum number of steps allocated */
420 xmlXPathStepOp *steps; /* ops for computation of this expression */
421 int last; /* index of last step in expression */
422 xmlChar *expr; /* the expression being computed */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000423#ifdef DEBUG_EVAL_COUNTS
424 int nb;
425 xmlChar *string;
426#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000427};
428
429/************************************************************************
430 * *
431 * Parser Type functions *
432 * *
433 ************************************************************************/
434
435/**
436 * xmlXPathNewCompExpr:
437 *
438 * Create a new Xpath component
439 *
440 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
441 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000442static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000443xmlXPathNewCompExpr(void) {
444 xmlXPathCompExprPtr cur;
445
446 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
447 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000448 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000449 return(NULL);
450 }
451 memset(cur, 0, sizeof(xmlXPathCompExpr));
452 cur->maxStep = 10;
453 cur->nbStep = 0;
454 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
455 sizeof(xmlXPathStepOp));
456 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000457 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000458 xmlFree(cur);
459 return(NULL);
460 }
461 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
462 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000463#ifdef DEBUG_EVAL_COUNTS
464 cur->nb = 0;
465#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000466 return(cur);
467}
468
469/**
470 * xmlXPathFreeCompExpr:
471 * @comp: an XPATH comp
472 *
473 * Free up the memory allocated by @comp
474 */
475void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000476xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
477{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000478 xmlXPathStepOpPtr op;
479 int i;
480
481 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000482 return;
483 for (i = 0; i < comp->nbStep; i++) {
484 op = &comp->steps[i];
485 if (op->value4 != NULL) {
486 if (op->op == XPATH_OP_VALUE)
487 xmlXPathFreeObject(op->value4);
488 else
489 xmlFree(op->value4);
490 }
491 if (op->value5 != NULL)
492 xmlFree(op->value5);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000493 }
494 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000495 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000496 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000497#ifdef DEBUG_EVAL_COUNTS
498 if (comp->string != NULL) {
499 xmlFree(comp->string);
500 }
501#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000502 if (comp->expr != NULL) {
503 xmlFree(comp->expr);
504 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000505
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000506 xmlFree(comp);
507}
508
509/**
510 * xmlXPathCompExprAdd:
511 * @comp: the compiled expression
512 * @ch1: first child index
513 * @ch2: second child index
514 * @op: an op
515 * @value: the first int value
516 * @value2: the second int value
517 * @value3: the third int value
518 * @value4: the first string value
519 * @value5: the second string value
520 *
William M. Brack08171912003-12-29 02:52:11 +0000521 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000522 *
523 * Returns -1 in case of failure, the index otherwise
524 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000525static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000526xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
527 xmlXPathOp op, int value,
528 int value2, int value3, void *value4, void *value5) {
529 if (comp->nbStep >= comp->maxStep) {
530 xmlXPathStepOp *real;
531
532 comp->maxStep *= 2;
533 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
534 comp->maxStep * sizeof(xmlXPathStepOp));
535 if (real == NULL) {
536 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000537 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000538 return(-1);
539 }
540 comp->steps = real;
541 }
542 comp->last = comp->nbStep;
543 comp->steps[comp->nbStep].ch1 = ch1;
544 comp->steps[comp->nbStep].ch2 = ch2;
545 comp->steps[comp->nbStep].op = op;
546 comp->steps[comp->nbStep].value = value;
547 comp->steps[comp->nbStep].value2 = value2;
548 comp->steps[comp->nbStep].value3 = value3;
549 comp->steps[comp->nbStep].value4 = value4;
550 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000551 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000552 return(comp->nbStep++);
553}
554
Daniel Veillardf06307e2001-07-03 10:35:50 +0000555/**
556 * xmlXPathCompSwap:
557 * @comp: the compiled expression
558 * @op: operation index
559 *
560 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000561 */
562static void
563xmlXPathCompSwap(xmlXPathStepOpPtr op) {
564 int tmp;
565
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000566#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000567 /*
568 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000569 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000570 * application
571 */
572 if (xmlXPathDisableOptimizer)
573 return;
574#endif
575
Daniel Veillardf06307e2001-07-03 10:35:50 +0000576 tmp = op->ch1;
577 op->ch1 = op->ch2;
578 op->ch2 = tmp;
579}
580
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000581#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
582 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
583 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000584#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
585 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
586 (op), (val), (val2), (val3), (val4), (val5))
587
588#define PUSH_LEAVE_EXPR(op, val, val2) \
589xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
590
591#define PUSH_UNARY_EXPR(op, ch, val, val2) \
592xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
593
594#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000595xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
596 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000597
598/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000599 * *
600 * Debugging related functions *
601 * *
602 ************************************************************************/
603
Owen Taylor3473f882001-02-23 17:55:21 +0000604#define STRANGE \
605 xmlGenericError(xmlGenericErrorContext, \
606 "Internal error at %s:%d\n", \
607 __FILE__, __LINE__);
608
609#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000610static void
611xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000612 int i;
613 char shift[100];
614
615 for (i = 0;((i < depth) && (i < 25));i++)
616 shift[2 * i] = shift[2 * i + 1] = ' ';
617 shift[2 * i] = shift[2 * i + 1] = 0;
618 if (cur == NULL) {
619 fprintf(output, shift);
620 fprintf(output, "Node is NULL !\n");
621 return;
622
623 }
624
625 if ((cur->type == XML_DOCUMENT_NODE) ||
626 (cur->type == XML_HTML_DOCUMENT_NODE)) {
627 fprintf(output, shift);
628 fprintf(output, " /\n");
629 } else if (cur->type == XML_ATTRIBUTE_NODE)
630 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
631 else
632 xmlDebugDumpOneNode(output, cur, depth);
633}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000634static void
635xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000636 xmlNodePtr tmp;
637 int i;
638 char shift[100];
639
640 for (i = 0;((i < depth) && (i < 25));i++)
641 shift[2 * i] = shift[2 * i + 1] = ' ';
642 shift[2 * i] = shift[2 * i + 1] = 0;
643 if (cur == NULL) {
644 fprintf(output, shift);
645 fprintf(output, "Node is NULL !\n");
646 return;
647
648 }
649
650 while (cur != NULL) {
651 tmp = cur;
652 cur = cur->next;
653 xmlDebugDumpOneNode(output, tmp, depth);
654 }
655}
Owen Taylor3473f882001-02-23 17:55:21 +0000656
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000657static void
658xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000659 int i;
660 char shift[100];
661
662 for (i = 0;((i < depth) && (i < 25));i++)
663 shift[2 * i] = shift[2 * i + 1] = ' ';
664 shift[2 * i] = shift[2 * i + 1] = 0;
665
666 if (cur == NULL) {
667 fprintf(output, shift);
668 fprintf(output, "NodeSet is NULL !\n");
669 return;
670
671 }
672
Daniel Veillard911f49a2001-04-07 15:39:35 +0000673 if (cur != NULL) {
674 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
675 for (i = 0;i < cur->nodeNr;i++) {
676 fprintf(output, shift);
677 fprintf(output, "%d", i + 1);
678 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
679 }
Owen Taylor3473f882001-02-23 17:55:21 +0000680 }
681}
682
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000683static void
684xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000685 int i;
686 char shift[100];
687
688 for (i = 0;((i < depth) && (i < 25));i++)
689 shift[2 * i] = shift[2 * i + 1] = ' ';
690 shift[2 * i] = shift[2 * i + 1] = 0;
691
692 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
693 fprintf(output, shift);
694 fprintf(output, "Value Tree is NULL !\n");
695 return;
696
697 }
698
699 fprintf(output, shift);
700 fprintf(output, "%d", i + 1);
701 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
702}
Owen Taylor3473f882001-02-23 17:55:21 +0000703#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000704static void
705xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000706 int i;
707 char shift[100];
708
709 for (i = 0;((i < depth) && (i < 25));i++)
710 shift[2 * i] = shift[2 * i + 1] = ' ';
711 shift[2 * i] = shift[2 * i + 1] = 0;
712
713 if (cur == NULL) {
714 fprintf(output, shift);
715 fprintf(output, "LocationSet is NULL !\n");
716 return;
717
718 }
719
720 for (i = 0;i < cur->locNr;i++) {
721 fprintf(output, shift);
722 fprintf(output, "%d : ", i + 1);
723 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
724 }
725}
Daniel Veillard017b1082001-06-21 11:20:21 +0000726#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000727
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000728/**
729 * xmlXPathDebugDumpObject:
730 * @output: the FILE * to dump the output
731 * @cur: the object to inspect
732 * @depth: indentation level
733 *
734 * Dump the content of the object for debugging purposes
735 */
736void
737xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000738 int i;
739 char shift[100];
740
741 for (i = 0;((i < depth) && (i < 25));i++)
742 shift[2 * i] = shift[2 * i + 1] = ' ';
743 shift[2 * i] = shift[2 * i + 1] = 0;
744
745 fprintf(output, shift);
746
747 if (cur == NULL) {
748 fprintf(output, "Object is empty (NULL)\n");
749 return;
750 }
751 switch(cur->type) {
752 case XPATH_UNDEFINED:
753 fprintf(output, "Object is uninitialized\n");
754 break;
755 case XPATH_NODESET:
756 fprintf(output, "Object is a Node Set :\n");
757 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
758 break;
759 case XPATH_XSLT_TREE:
760 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000761 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000762 break;
763 case XPATH_BOOLEAN:
764 fprintf(output, "Object is a Boolean : ");
765 if (cur->boolval) fprintf(output, "true\n");
766 else fprintf(output, "false\n");
767 break;
768 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000769 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000770 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000771 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000772 break;
773 case -1:
774 fprintf(output, "Object is a number : -Infinity\n");
775 break;
776 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000777 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000778 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000779 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
780 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000781 } else {
782 fprintf(output, "Object is a number : %0g\n", cur->floatval);
783 }
784 }
Owen Taylor3473f882001-02-23 17:55:21 +0000785 break;
786 case XPATH_STRING:
787 fprintf(output, "Object is a string : ");
788 xmlDebugDumpString(output, cur->stringval);
789 fprintf(output, "\n");
790 break;
791 case XPATH_POINT:
792 fprintf(output, "Object is a point : index %d in node", cur->index);
793 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
794 fprintf(output, "\n");
795 break;
796 case XPATH_RANGE:
797 if ((cur->user2 == NULL) ||
798 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
799 fprintf(output, "Object is a collapsed range :\n");
800 fprintf(output, shift);
801 if (cur->index >= 0)
802 fprintf(output, "index %d in ", cur->index);
803 fprintf(output, "node\n");
804 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
805 depth + 1);
806 } else {
807 fprintf(output, "Object is a range :\n");
808 fprintf(output, shift);
809 fprintf(output, "From ");
810 if (cur->index >= 0)
811 fprintf(output, "index %d in ", cur->index);
812 fprintf(output, "node\n");
813 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
814 depth + 1);
815 fprintf(output, shift);
816 fprintf(output, "To ");
817 if (cur->index2 >= 0)
818 fprintf(output, "index %d in ", cur->index2);
819 fprintf(output, "node\n");
820 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
821 depth + 1);
822 fprintf(output, "\n");
823 }
824 break;
825 case XPATH_LOCATIONSET:
826#if defined(LIBXML_XPTR_ENABLED)
827 fprintf(output, "Object is a Location Set:\n");
828 xmlXPathDebugDumpLocationSet(output,
829 (xmlLocationSetPtr) cur->user, depth);
830#endif
831 break;
832 case XPATH_USERS:
833 fprintf(output, "Object is user defined\n");
834 break;
835 }
836}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000837
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000838static void
839xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000840 xmlXPathStepOpPtr op, int depth) {
841 int i;
842 char shift[100];
843
844 for (i = 0;((i < depth) && (i < 25));i++)
845 shift[2 * i] = shift[2 * i + 1] = ' ';
846 shift[2 * i] = shift[2 * i + 1] = 0;
847
848 fprintf(output, shift);
849 if (op == NULL) {
850 fprintf(output, "Step is NULL\n");
851 return;
852 }
853 switch (op->op) {
854 case XPATH_OP_END:
855 fprintf(output, "END"); break;
856 case XPATH_OP_AND:
857 fprintf(output, "AND"); break;
858 case XPATH_OP_OR:
859 fprintf(output, "OR"); break;
860 case XPATH_OP_EQUAL:
861 if (op->value)
862 fprintf(output, "EQUAL =");
863 else
864 fprintf(output, "EQUAL !=");
865 break;
866 case XPATH_OP_CMP:
867 if (op->value)
868 fprintf(output, "CMP <");
869 else
870 fprintf(output, "CMP >");
871 if (!op->value2)
872 fprintf(output, "=");
873 break;
874 case XPATH_OP_PLUS:
875 if (op->value == 0)
876 fprintf(output, "PLUS -");
877 else if (op->value == 1)
878 fprintf(output, "PLUS +");
879 else if (op->value == 2)
880 fprintf(output, "PLUS unary -");
881 else if (op->value == 3)
882 fprintf(output, "PLUS unary - -");
883 break;
884 case XPATH_OP_MULT:
885 if (op->value == 0)
886 fprintf(output, "MULT *");
887 else if (op->value == 1)
888 fprintf(output, "MULT div");
889 else
890 fprintf(output, "MULT mod");
891 break;
892 case XPATH_OP_UNION:
893 fprintf(output, "UNION"); break;
894 case XPATH_OP_ROOT:
895 fprintf(output, "ROOT"); break;
896 case XPATH_OP_NODE:
897 fprintf(output, "NODE"); break;
898 case XPATH_OP_RESET:
899 fprintf(output, "RESET"); break;
900 case XPATH_OP_SORT:
901 fprintf(output, "SORT"); break;
902 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000903 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
904 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
905 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000906 const xmlChar *prefix = op->value4;
907 const xmlChar *name = op->value5;
908
909 fprintf(output, "COLLECT ");
910 switch (axis) {
911 case AXIS_ANCESTOR:
912 fprintf(output, " 'ancestors' "); break;
913 case AXIS_ANCESTOR_OR_SELF:
914 fprintf(output, " 'ancestors-or-self' "); break;
915 case AXIS_ATTRIBUTE:
916 fprintf(output, " 'attributes' "); break;
917 case AXIS_CHILD:
918 fprintf(output, " 'child' "); break;
919 case AXIS_DESCENDANT:
920 fprintf(output, " 'descendant' "); break;
921 case AXIS_DESCENDANT_OR_SELF:
922 fprintf(output, " 'descendant-or-self' "); break;
923 case AXIS_FOLLOWING:
924 fprintf(output, " 'following' "); break;
925 case AXIS_FOLLOWING_SIBLING:
926 fprintf(output, " 'following-siblings' "); break;
927 case AXIS_NAMESPACE:
928 fprintf(output, " 'namespace' "); break;
929 case AXIS_PARENT:
930 fprintf(output, " 'parent' "); break;
931 case AXIS_PRECEDING:
932 fprintf(output, " 'preceding' "); break;
933 case AXIS_PRECEDING_SIBLING:
934 fprintf(output, " 'preceding-sibling' "); break;
935 case AXIS_SELF:
936 fprintf(output, " 'self' "); break;
937 }
938 switch (test) {
939 case NODE_TEST_NONE:
940 fprintf(output, "'none' "); break;
941 case NODE_TEST_TYPE:
942 fprintf(output, "'type' "); break;
943 case NODE_TEST_PI:
944 fprintf(output, "'PI' "); break;
945 case NODE_TEST_ALL:
946 fprintf(output, "'all' "); break;
947 case NODE_TEST_NS:
948 fprintf(output, "'namespace' "); break;
949 case NODE_TEST_NAME:
950 fprintf(output, "'name' "); break;
951 }
952 switch (type) {
953 case NODE_TYPE_NODE:
954 fprintf(output, "'node' "); break;
955 case NODE_TYPE_COMMENT:
956 fprintf(output, "'comment' "); break;
957 case NODE_TYPE_TEXT:
958 fprintf(output, "'text' "); break;
959 case NODE_TYPE_PI:
960 fprintf(output, "'PI' "); break;
961 }
962 if (prefix != NULL)
963 fprintf(output, "%s:", prefix);
964 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +0000965 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000966 break;
967
968 }
969 case XPATH_OP_VALUE: {
970 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
971
972 fprintf(output, "ELEM ");
973 xmlXPathDebugDumpObject(output, object, 0);
974 goto finish;
975 }
976 case XPATH_OP_VARIABLE: {
977 const xmlChar *prefix = op->value5;
978 const xmlChar *name = op->value4;
979
980 if (prefix != NULL)
981 fprintf(output, "VARIABLE %s:%s", prefix, name);
982 else
983 fprintf(output, "VARIABLE %s", name);
984 break;
985 }
986 case XPATH_OP_FUNCTION: {
987 int nbargs = op->value;
988 const xmlChar *prefix = op->value5;
989 const xmlChar *name = op->value4;
990
991 if (prefix != NULL)
992 fprintf(output, "FUNCTION %s:%s(%d args)",
993 prefix, name, nbargs);
994 else
995 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
996 break;
997 }
998 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
999 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001000 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001001#ifdef LIBXML_XPTR_ENABLED
1002 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1003#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001004 default:
1005 fprintf(output, "UNKNOWN %d\n", op->op); return;
1006 }
1007 fprintf(output, "\n");
1008finish:
1009 if (op->ch1 >= 0)
1010 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1011 if (op->ch2 >= 0)
1012 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1013}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001014
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001015/**
1016 * xmlXPathDebugDumpCompExpr:
1017 * @output: the FILE * for the output
1018 * @comp: the precompiled XPath expression
1019 * @depth: the indentation level.
1020 *
1021 * Dumps the tree of the compiled XPath expression.
1022 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001023void
1024xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1025 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001026 int i;
1027 char shift[100];
1028
1029 for (i = 0;((i < depth) && (i < 25));i++)
1030 shift[2 * i] = shift[2 * i + 1] = ' ';
1031 shift[2 * i] = shift[2 * i + 1] = 0;
1032
1033 fprintf(output, shift);
1034
1035 if (comp == NULL) {
1036 fprintf(output, "Compiled Expression is NULL\n");
1037 return;
1038 }
1039 fprintf(output, "Compiled Expression : %d elements\n",
1040 comp->nbStep);
1041 i = comp->last;
1042 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1043}
Daniel Veillard017b1082001-06-21 11:20:21 +00001044#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001045
1046/************************************************************************
1047 * *
1048 * Parser stacks related functions and macros *
1049 * *
1050 ************************************************************************/
1051
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001052/**
1053 * valuePop:
1054 * @ctxt: an XPath evaluation context
1055 *
1056 * Pops the top XPath object from the value stack
1057 *
1058 * Returns the XPath object just removed
1059 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001060extern xmlXPathObjectPtr
1061valuePop(xmlXPathParserContextPtr ctxt)
1062{
1063 xmlXPathObjectPtr ret;
1064
1065 if (ctxt->valueNr <= 0)
1066 return (0);
1067 ctxt->valueNr--;
1068 if (ctxt->valueNr > 0)
1069 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1070 else
1071 ctxt->value = NULL;
1072 ret = ctxt->valueTab[ctxt->valueNr];
1073 ctxt->valueTab[ctxt->valueNr] = 0;
1074 return (ret);
1075}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001076/**
1077 * valuePush:
1078 * @ctxt: an XPath evaluation context
1079 * @value: the XPath object
1080 *
1081 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001082 *
1083 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001084 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001085extern int
1086valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1087{
1088 if (ctxt->valueNr >= ctxt->valueMax) {
1089 ctxt->valueMax *= 2;
1090 ctxt->valueTab =
1091 (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1092 ctxt->valueMax *
1093 sizeof(ctxt->valueTab[0]));
1094 if (ctxt->valueTab == NULL) {
1095 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1096 return (0);
1097 }
1098 }
1099 ctxt->valueTab[ctxt->valueNr] = value;
1100 ctxt->value = value;
1101 return (ctxt->valueNr++);
1102}
Owen Taylor3473f882001-02-23 17:55:21 +00001103
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001104/**
1105 * xmlXPathPopBoolean:
1106 * @ctxt: an XPath parser context
1107 *
1108 * Pops a boolean from the stack, handling conversion if needed.
1109 * Check error with #xmlXPathCheckError.
1110 *
1111 * Returns the boolean
1112 */
1113int
1114xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1115 xmlXPathObjectPtr obj;
1116 int ret;
1117
1118 obj = valuePop(ctxt);
1119 if (obj == NULL) {
1120 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1121 return(0);
1122 }
William M. Brack08171912003-12-29 02:52:11 +00001123 if (obj->type != XPATH_BOOLEAN)
1124 ret = xmlXPathCastToBoolean(obj);
1125 else
1126 ret = obj->boolval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001127 xmlXPathFreeObject(obj);
1128 return(ret);
1129}
1130
1131/**
1132 * xmlXPathPopNumber:
1133 * @ctxt: an XPath parser context
1134 *
1135 * Pops a number from the stack, handling conversion if needed.
1136 * Check error with #xmlXPathCheckError.
1137 *
1138 * Returns the number
1139 */
1140double
1141xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1142 xmlXPathObjectPtr obj;
1143 double ret;
1144
1145 obj = valuePop(ctxt);
1146 if (obj == NULL) {
1147 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1148 return(0);
1149 }
William M. Brack08171912003-12-29 02:52:11 +00001150 if (obj->type != XPATH_NUMBER)
1151 ret = xmlXPathCastToNumber(obj);
1152 else
1153 ret = obj->floatval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001154 xmlXPathFreeObject(obj);
1155 return(ret);
1156}
1157
1158/**
1159 * xmlXPathPopString:
1160 * @ctxt: an XPath parser context
1161 *
1162 * Pops a string from the stack, handling conversion if needed.
1163 * Check error with #xmlXPathCheckError.
1164 *
1165 * Returns the string
1166 */
1167xmlChar *
1168xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1169 xmlXPathObjectPtr obj;
1170 xmlChar * ret;
1171
1172 obj = valuePop(ctxt);
1173 if (obj == NULL) {
1174 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1175 return(NULL);
1176 }
William M. Brack08171912003-12-29 02:52:11 +00001177 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001178 /* TODO: needs refactoring somewhere else */
1179 if (obj->stringval == ret)
1180 obj->stringval = NULL;
1181 xmlXPathFreeObject(obj);
1182 return(ret);
1183}
1184
1185/**
1186 * xmlXPathPopNodeSet:
1187 * @ctxt: an XPath parser context
1188 *
1189 * Pops a node-set from the stack, handling conversion if needed.
1190 * Check error with #xmlXPathCheckError.
1191 *
1192 * Returns the node-set
1193 */
1194xmlNodeSetPtr
1195xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1196 xmlXPathObjectPtr obj;
1197 xmlNodeSetPtr ret;
1198
1199 if (ctxt->value == NULL) {
1200 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1201 return(NULL);
1202 }
1203 if (!xmlXPathStackIsNodeSet(ctxt)) {
1204 xmlXPathSetTypeError(ctxt);
1205 return(NULL);
1206 }
1207 obj = valuePop(ctxt);
1208 ret = obj->nodesetval;
Daniel Veillard9deb2422003-07-28 20:40:59 +00001209 /* to fix memory leak of not clearing obj->user */
1210 if (obj->boolval && obj->user != NULL)
1211 xmlFreeNodeList((xmlNodePtr) obj->user);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001212 xmlXPathFreeNodeSetList(obj);
1213 return(ret);
1214}
1215
1216/**
1217 * xmlXPathPopExternal:
1218 * @ctxt: an XPath parser context
1219 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001220 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001221 * Check error with #xmlXPathCheckError.
1222 *
1223 * Returns the object
1224 */
1225void *
1226xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1227 xmlXPathObjectPtr obj;
1228 void * ret;
1229
1230 if (ctxt->value == NULL) {
1231 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1232 return(NULL);
1233 }
1234 if (ctxt->value->type != XPATH_USERS) {
1235 xmlXPathSetTypeError(ctxt);
1236 return(NULL);
1237 }
1238 obj = valuePop(ctxt);
1239 ret = obj->user;
1240 xmlXPathFreeObject(obj);
1241 return(ret);
1242}
1243
Owen Taylor3473f882001-02-23 17:55:21 +00001244/*
1245 * Macros for accessing the content. Those should be used only by the parser,
1246 * and not exported.
1247 *
1248 * Dirty macros, i.e. one need to make assumption on the context to use them
1249 *
1250 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1251 * CUR returns the current xmlChar value, i.e. a 8 bit value
1252 * in ISO-Latin or UTF-8.
1253 * This should be used internally by the parser
1254 * only to compare to ASCII values otherwise it would break when
1255 * running with UTF-8 encoding.
1256 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1257 * to compare on ASCII based substring.
1258 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1259 * strings within the parser.
1260 * CURRENT Returns the current char value, with the full decoding of
1261 * UTF-8 if we are using this mode. It returns an int.
1262 * NEXT Skip to the next character, this does the proper decoding
1263 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1264 * It returns the pointer to the current xmlChar.
1265 */
1266
1267#define CUR (*ctxt->cur)
1268#define SKIP(val) ctxt->cur += (val)
1269#define NXT(val) ctxt->cur[(val)]
1270#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001271#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1272
1273#define COPY_BUF(l,b,i,v) \
1274 if (l == 1) b[i++] = (xmlChar) v; \
1275 else i += xmlCopyChar(l,&b[i],v)
1276
1277#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001278
1279#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001280 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001281
1282#define CURRENT (*ctxt->cur)
1283#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1284
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001285
1286#ifndef DBL_DIG
1287#define DBL_DIG 16
1288#endif
1289#ifndef DBL_EPSILON
1290#define DBL_EPSILON 1E-9
1291#endif
1292
1293#define UPPER_DOUBLE 1E9
1294#define LOWER_DOUBLE 1E-5
1295
1296#define INTEGER_DIGITS DBL_DIG
1297#define FRACTION_DIGITS (DBL_DIG + 1)
1298#define EXPONENT_DIGITS (3 + 2)
1299
1300/**
1301 * xmlXPathFormatNumber:
1302 * @number: number to format
1303 * @buffer: output buffer
1304 * @buffersize: size of output buffer
1305 *
1306 * Convert the number into a string representation.
1307 */
1308static void
1309xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1310{
Daniel Veillardcda96922001-08-21 10:56:31 +00001311 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001312 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001313 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001314 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001315 break;
1316 case -1:
1317 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001318 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001319 break;
1320 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001321 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001322 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001323 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001324 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001325 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001326 } else if (number == ((int) number)) {
1327 char work[30];
1328 char *ptr, *cur;
1329 int res, value = (int) number;
1330
1331 ptr = &buffer[0];
1332 if (value < 0) {
1333 *ptr++ = '-';
1334 value = -value;
1335 }
1336 if (value == 0) {
1337 *ptr++ = '0';
1338 } else {
1339 cur = &work[0];
1340 while (value != 0) {
1341 res = value % 10;
1342 value = value / 10;
1343 *cur++ = '0' + res;
1344 }
1345 cur--;
1346 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1347 *ptr++ = *cur--;
1348 }
1349 }
1350 if (ptr - buffer < buffersize) {
1351 *ptr = 0;
1352 } else if (buffersize > 0) {
1353 ptr--;
1354 *ptr = 0;
1355 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001356 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001357 /* 3 is sign, decimal point, and terminating zero */
1358 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1359 int integer_place, fraction_place;
1360 char *ptr;
1361 char *after_fraction;
1362 double absolute_value;
1363 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001364
Bjorn Reese70a9da52001-04-21 16:57:29 +00001365 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001366
Bjorn Reese70a9da52001-04-21 16:57:29 +00001367 /*
1368 * First choose format - scientific or regular floating point.
1369 * In either case, result is in work, and after_fraction points
1370 * just past the fractional part.
1371 */
1372 if ( ((absolute_value > UPPER_DOUBLE) ||
1373 (absolute_value < LOWER_DOUBLE)) &&
1374 (absolute_value != 0.0) ) {
1375 /* Use scientific notation */
1376 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1377 fraction_place = DBL_DIG - 1;
1378 snprintf(work, sizeof(work),"%*.*e",
1379 integer_place, fraction_place, number);
1380 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001381 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001382 else {
1383 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001384 if (absolute_value > 0.0)
1385 integer_place = 1 + (int)log10(absolute_value);
1386 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001387 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001388 fraction_place = (integer_place > 0)
1389 ? DBL_DIG - integer_place
1390 : DBL_DIG;
1391 size = snprintf(work, sizeof(work), "%0.*f",
1392 fraction_place, number);
1393 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001394 }
1395
Bjorn Reese70a9da52001-04-21 16:57:29 +00001396 /* Remove fractional trailing zeroes */
1397 ptr = after_fraction;
1398 while (*(--ptr) == '0')
1399 ;
1400 if (*ptr != '.')
1401 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001402 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001403
1404 /* Finally copy result back to caller */
1405 size = strlen(work) + 1;
1406 if (size > buffersize) {
1407 work[buffersize - 1] = 0;
1408 size = buffersize;
1409 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001410 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001411 }
1412 break;
1413 }
1414}
1415
Owen Taylor3473f882001-02-23 17:55:21 +00001416
1417/************************************************************************
1418 * *
1419 * Routines to handle NodeSets *
1420 * *
1421 ************************************************************************/
1422
1423/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001424 * xmlXPathOrderDocElems:
1425 * @doc: an input document
1426 *
1427 * Call this routine to speed up XPath computation on static documents.
1428 * This stamps all the element nodes with the document order
1429 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00001430 * field, the value stored is actually - the node number (starting at -1)
1431 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001432 *
William M. Brack08171912003-12-29 02:52:11 +00001433 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001434 * of error.
1435 */
1436long
1437xmlXPathOrderDocElems(xmlDocPtr doc) {
1438 long count = 0;
1439 xmlNodePtr cur;
1440
1441 if (doc == NULL)
1442 return(-1);
1443 cur = doc->children;
1444 while (cur != NULL) {
1445 if (cur->type == XML_ELEMENT_NODE) {
1446 cur->content = (void *) (-(++count));
1447 if (cur->children != NULL) {
1448 cur = cur->children;
1449 continue;
1450 }
1451 }
1452 if (cur->next != NULL) {
1453 cur = cur->next;
1454 continue;
1455 }
1456 do {
1457 cur = cur->parent;
1458 if (cur == NULL)
1459 break;
1460 if (cur == (xmlNodePtr) doc) {
1461 cur = NULL;
1462 break;
1463 }
1464 if (cur->next != NULL) {
1465 cur = cur->next;
1466 break;
1467 }
1468 } while (cur != NULL);
1469 }
1470 return(count);
1471}
1472
1473/**
Owen Taylor3473f882001-02-23 17:55:21 +00001474 * xmlXPathCmpNodes:
1475 * @node1: the first node
1476 * @node2: the second node
1477 *
1478 * Compare two nodes w.r.t document order
1479 *
1480 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00001481 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001482 */
1483int
1484xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1485 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001486 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001487 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001488 xmlNodePtr cur, root;
1489
1490 if ((node1 == NULL) || (node2 == NULL))
1491 return(-2);
1492 /*
1493 * a couple of optimizations which will avoid computations in most cases
1494 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001495 if (node1->type == XML_ATTRIBUTE_NODE) {
1496 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001497 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001498 node1 = node1->parent;
1499 }
1500 if (node2->type == XML_ATTRIBUTE_NODE) {
1501 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001502 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001503 node2 = node2->parent;
1504 }
1505 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001506 if (attr1 == attr2) {
1507 /* not required, but we keep attributes in order */
1508 if (attr1 != 0) {
1509 cur = attrNode2->prev;
1510 while (cur != NULL) {
1511 if (cur == attrNode1)
1512 return (1);
1513 cur = cur->prev;
1514 }
1515 return (-1);
1516 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001517 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001518 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001519 if (attr2 == 1)
1520 return(1);
1521 return(-1);
1522 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001523 if ((node1->type == XML_NAMESPACE_DECL) ||
1524 (node2->type == XML_NAMESPACE_DECL))
1525 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001526 if (node1 == node2->prev)
1527 return(1);
1528 if (node1 == node2->next)
1529 return(-1);
1530
1531 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001532 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001533 */
1534 if ((node1->type == XML_ELEMENT_NODE) &&
1535 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001536 (0 > (long) node1->content) &&
1537 (0 > (long) node2->content) &&
1538 (node1->doc == node2->doc)) {
1539 long l1, l2;
1540
1541 l1 = -((long) node1->content);
1542 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001543 if (l1 < l2)
1544 return(1);
1545 if (l1 > l2)
1546 return(-1);
1547 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001548
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001549 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001550 * compute depth to root
1551 */
1552 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1553 if (cur == node1)
1554 return(1);
1555 depth2++;
1556 }
1557 root = cur;
1558 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1559 if (cur == node2)
1560 return(-1);
1561 depth1++;
1562 }
1563 /*
1564 * Distinct document (or distinct entities :-( ) case.
1565 */
1566 if (root != cur) {
1567 return(-2);
1568 }
1569 /*
1570 * get the nearest common ancestor.
1571 */
1572 while (depth1 > depth2) {
1573 depth1--;
1574 node1 = node1->parent;
1575 }
1576 while (depth2 > depth1) {
1577 depth2--;
1578 node2 = node2->parent;
1579 }
1580 while (node1->parent != node2->parent) {
1581 node1 = node1->parent;
1582 node2 = node2->parent;
1583 /* should not happen but just in case ... */
1584 if ((node1 == NULL) || (node2 == NULL))
1585 return(-2);
1586 }
1587 /*
1588 * Find who's first.
1589 */
1590 if (node1 == node2->next)
1591 return(-1);
1592 for (cur = node1->next;cur != NULL;cur = cur->next)
1593 if (cur == node2)
1594 return(1);
1595 return(-1); /* assume there is no sibling list corruption */
1596}
1597
1598/**
1599 * xmlXPathNodeSetSort:
1600 * @set: the node set
1601 *
1602 * Sort the node set in document order
1603 */
1604void
1605xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001606 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001607 xmlNodePtr tmp;
1608
1609 if (set == NULL)
1610 return;
1611
1612 /* Use Shell's sort to sort the node-set */
1613 len = set->nodeNr;
1614 for (incr = len / 2; incr > 0; incr /= 2) {
1615 for (i = incr; i < len; i++) {
1616 j = i - incr;
1617 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001618 if (xmlXPathCmpNodes(set->nodeTab[j],
1619 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001620 tmp = set->nodeTab[j];
1621 set->nodeTab[j] = set->nodeTab[j + incr];
1622 set->nodeTab[j + incr] = tmp;
1623 j -= incr;
1624 } else
1625 break;
1626 }
1627 }
1628 }
1629}
1630
1631#define XML_NODESET_DEFAULT 10
1632/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001633 * xmlXPathNodeSetDupNs:
1634 * @node: the parent node of the namespace XPath node
1635 * @ns: the libxml namespace declaration node.
1636 *
1637 * Namespace node in libxml don't match the XPath semantic. In a node set
1638 * the namespace nodes are duplicated and the next pointer is set to the
1639 * parent node in the XPath semantic.
1640 *
1641 * Returns the newly created object.
1642 */
1643static xmlNodePtr
1644xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1645 xmlNsPtr cur;
1646
1647 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1648 return(NULL);
1649 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1650 return((xmlNodePtr) ns);
1651
1652 /*
1653 * Allocate a new Namespace and fill the fields.
1654 */
1655 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1656 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001657 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001658 return(NULL);
1659 }
1660 memset(cur, 0, sizeof(xmlNs));
1661 cur->type = XML_NAMESPACE_DECL;
1662 if (ns->href != NULL)
1663 cur->href = xmlStrdup(ns->href);
1664 if (ns->prefix != NULL)
1665 cur->prefix = xmlStrdup(ns->prefix);
1666 cur->next = (xmlNsPtr) node;
1667 return((xmlNodePtr) cur);
1668}
1669
1670/**
1671 * xmlXPathNodeSetFreeNs:
1672 * @ns: the XPath namespace node found in a nodeset.
1673 *
William M. Brack08171912003-12-29 02:52:11 +00001674 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001675 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00001676 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001677 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001678void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001679xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1680 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1681 return;
1682
1683 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1684 if (ns->href != NULL)
1685 xmlFree((xmlChar *)ns->href);
1686 if (ns->prefix != NULL)
1687 xmlFree((xmlChar *)ns->prefix);
1688 xmlFree(ns);
1689 }
1690}
1691
1692/**
Owen Taylor3473f882001-02-23 17:55:21 +00001693 * xmlXPathNodeSetCreate:
1694 * @val: an initial xmlNodePtr, or NULL
1695 *
1696 * Create a new xmlNodeSetPtr of type double and of value @val
1697 *
1698 * Returns the newly created object.
1699 */
1700xmlNodeSetPtr
1701xmlXPathNodeSetCreate(xmlNodePtr val) {
1702 xmlNodeSetPtr ret;
1703
1704 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1705 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001706 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001707 return(NULL);
1708 }
1709 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1710 if (val != NULL) {
1711 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1712 sizeof(xmlNodePtr));
1713 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001714 xmlXPathErrMemory(NULL, "creating nodeset\n");
1715 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001716 return(NULL);
1717 }
1718 memset(ret->nodeTab, 0 ,
1719 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1720 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001721 if (val->type == XML_NAMESPACE_DECL) {
1722 xmlNsPtr ns = (xmlNsPtr) val;
1723
1724 ret->nodeTab[ret->nodeNr++] =
1725 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1726 } else
1727 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001728 }
1729 return(ret);
1730}
1731
1732/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001733 * xmlXPathNodeSetContains:
1734 * @cur: the node-set
1735 * @val: the node
1736 *
1737 * checks whether @cur contains @val
1738 *
1739 * Returns true (1) if @cur contains @val, false (0) otherwise
1740 */
1741int
1742xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1743 int i;
1744
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001745 if (val->type == XML_NAMESPACE_DECL) {
1746 for (i = 0; i < cur->nodeNr; i++) {
1747 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1748 xmlNsPtr ns1, ns2;
1749
1750 ns1 = (xmlNsPtr) val;
1751 ns2 = (xmlNsPtr) cur->nodeTab[i];
1752 if (ns1 == ns2)
1753 return(1);
1754 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1755 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1756 return(1);
1757 }
1758 }
1759 } else {
1760 for (i = 0; i < cur->nodeNr; i++) {
1761 if (cur->nodeTab[i] == val)
1762 return(1);
1763 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001764 }
1765 return(0);
1766}
1767
1768/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001769 * xmlXPathNodeSetAddNs:
1770 * @cur: the initial node set
1771 * @node: the hosting node
1772 * @ns: a the namespace node
1773 *
1774 * add a new namespace node to an existing NodeSet
1775 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001776void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001777xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1778 int i;
1779
1780 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1781 (node->type != XML_ELEMENT_NODE))
1782 return;
1783
William M. Brack08171912003-12-29 02:52:11 +00001784 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001785 /*
William M. Brack08171912003-12-29 02:52:11 +00001786 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001787 */
1788 for (i = 0;i < cur->nodeNr;i++) {
1789 if ((cur->nodeTab[i] != NULL) &&
1790 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001791 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001792 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1793 return;
1794 }
1795
1796 /*
1797 * grow the nodeTab if needed
1798 */
1799 if (cur->nodeMax == 0) {
1800 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1801 sizeof(xmlNodePtr));
1802 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001803 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001804 return;
1805 }
1806 memset(cur->nodeTab, 0 ,
1807 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1808 cur->nodeMax = XML_NODESET_DEFAULT;
1809 } else if (cur->nodeNr == cur->nodeMax) {
1810 xmlNodePtr *temp;
1811
1812 cur->nodeMax *= 2;
1813 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1814 sizeof(xmlNodePtr));
1815 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001816 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001817 return;
1818 }
1819 cur->nodeTab = temp;
1820 }
1821 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1822}
1823
1824/**
Owen Taylor3473f882001-02-23 17:55:21 +00001825 * xmlXPathNodeSetAdd:
1826 * @cur: the initial node set
1827 * @val: a new xmlNodePtr
1828 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001829 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001830 */
1831void
1832xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1833 int i;
1834
1835 if (val == NULL) return;
1836
Daniel Veillardef0b4502003-03-24 13:57:34 +00001837#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001838 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1839 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001840#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001841
William M. Brack08171912003-12-29 02:52:11 +00001842 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001843 /*
William M. Brack08171912003-12-29 02:52:11 +00001844 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00001845 */
1846 for (i = 0;i < cur->nodeNr;i++)
1847 if (cur->nodeTab[i] == val) return;
1848
1849 /*
1850 * grow the nodeTab if needed
1851 */
1852 if (cur->nodeMax == 0) {
1853 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1854 sizeof(xmlNodePtr));
1855 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001856 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001857 return;
1858 }
1859 memset(cur->nodeTab, 0 ,
1860 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1861 cur->nodeMax = XML_NODESET_DEFAULT;
1862 } else if (cur->nodeNr == cur->nodeMax) {
1863 xmlNodePtr *temp;
1864
1865 cur->nodeMax *= 2;
1866 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1867 sizeof(xmlNodePtr));
1868 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001869 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001870 return;
1871 }
1872 cur->nodeTab = temp;
1873 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001874 if (val->type == XML_NAMESPACE_DECL) {
1875 xmlNsPtr ns = (xmlNsPtr) val;
1876
1877 cur->nodeTab[cur->nodeNr++] =
1878 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1879 } else
1880 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001881}
1882
1883/**
1884 * xmlXPathNodeSetAddUnique:
1885 * @cur: the initial node set
1886 * @val: a new xmlNodePtr
1887 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001888 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001889 * when we are sure the node is not already in the set.
1890 */
1891void
1892xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1893 if (val == NULL) return;
1894
Daniel Veillardef0b4502003-03-24 13:57:34 +00001895#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001896 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1897 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001898#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001899
William M. Brack08171912003-12-29 02:52:11 +00001900 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001901 /*
1902 * grow the nodeTab if needed
1903 */
1904 if (cur->nodeMax == 0) {
1905 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1906 sizeof(xmlNodePtr));
1907 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001908 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001909 return;
1910 }
1911 memset(cur->nodeTab, 0 ,
1912 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1913 cur->nodeMax = XML_NODESET_DEFAULT;
1914 } else if (cur->nodeNr == cur->nodeMax) {
1915 xmlNodePtr *temp;
1916
1917 cur->nodeMax *= 2;
1918 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1919 sizeof(xmlNodePtr));
1920 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001921 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001922 return;
1923 }
1924 cur->nodeTab = temp;
1925 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001926 if (val->type == XML_NAMESPACE_DECL) {
1927 xmlNsPtr ns = (xmlNsPtr) val;
1928
1929 cur->nodeTab[cur->nodeNr++] =
1930 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1931 } else
1932 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001933}
1934
1935/**
1936 * xmlXPathNodeSetMerge:
1937 * @val1: the first NodeSet or NULL
1938 * @val2: the second NodeSet
1939 *
1940 * Merges two nodesets, all nodes from @val2 are added to @val1
1941 * if @val1 is NULL, a new set is created and copied from @val2
1942 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001943 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001944 */
1945xmlNodeSetPtr
1946xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001947 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001948
1949 if (val2 == NULL) return(val1);
1950 if (val1 == NULL) {
1951 val1 = xmlXPathNodeSetCreate(NULL);
1952 }
1953
William M. Brack08171912003-12-29 02:52:11 +00001954 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001955 initNr = val1->nodeNr;
1956
1957 for (i = 0;i < val2->nodeNr;i++) {
1958 /*
William M. Brack08171912003-12-29 02:52:11 +00001959 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00001960 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001961 skip = 0;
1962 for (j = 0; j < initNr; j++) {
1963 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1964 skip = 1;
1965 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001966 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1967 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1968 xmlNsPtr ns1, ns2;
1969 ns1 = (xmlNsPtr) val1->nodeTab[j];
1970 ns2 = (xmlNsPtr) val2->nodeTab[i];
1971 if ((ns1->next == ns2->next) &&
1972 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1973 skip = 1;
1974 break;
1975 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001976 }
1977 }
1978 if (skip)
1979 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001980
1981 /*
1982 * grow the nodeTab if needed
1983 */
1984 if (val1->nodeMax == 0) {
1985 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1986 sizeof(xmlNodePtr));
1987 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001988 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001989 return(NULL);
1990 }
1991 memset(val1->nodeTab, 0 ,
1992 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1993 val1->nodeMax = XML_NODESET_DEFAULT;
1994 } else if (val1->nodeNr == val1->nodeMax) {
1995 xmlNodePtr *temp;
1996
1997 val1->nodeMax *= 2;
1998 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1999 sizeof(xmlNodePtr));
2000 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002001 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002002 return(NULL);
2003 }
2004 val1->nodeTab = temp;
2005 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002006 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2007 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2008
2009 val1->nodeTab[val1->nodeNr++] =
2010 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2011 } else
2012 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002013 }
2014
2015 return(val1);
2016}
2017
2018/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002019 * xmlXPathNodeSetMergeUnique:
2020 * @val1: the first NodeSet or NULL
2021 * @val2: the second NodeSet
2022 *
2023 * Merges two nodesets, all nodes from @val2 are added to @val1
2024 * if @val1 is NULL, a new set is created and copied from @val2
2025 *
2026 * Returns @val1 once extended or NULL in case of error.
2027 */
2028static xmlNodeSetPtr
2029xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002030 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002031
2032 if (val2 == NULL) return(val1);
2033 if (val1 == NULL) {
2034 val1 = xmlXPathNodeSetCreate(NULL);
2035 }
2036
William M. Brack08171912003-12-29 02:52:11 +00002037 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002038
2039 for (i = 0;i < val2->nodeNr;i++) {
2040 /*
2041 * grow the nodeTab if needed
2042 */
2043 if (val1->nodeMax == 0) {
2044 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2045 sizeof(xmlNodePtr));
2046 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002047 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002048 return(NULL);
2049 }
2050 memset(val1->nodeTab, 0 ,
2051 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2052 val1->nodeMax = XML_NODESET_DEFAULT;
2053 } else if (val1->nodeNr == val1->nodeMax) {
2054 xmlNodePtr *temp;
2055
2056 val1->nodeMax *= 2;
2057 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2058 sizeof(xmlNodePtr));
2059 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002060 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002061 return(NULL);
2062 }
2063 val1->nodeTab = temp;
2064 }
2065 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2066 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2067
2068 val1->nodeTab[val1->nodeNr++] =
2069 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2070 } else
2071 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2072 }
2073
2074 return(val1);
2075}
2076
2077/**
Owen Taylor3473f882001-02-23 17:55:21 +00002078 * xmlXPathNodeSetDel:
2079 * @cur: the initial node set
2080 * @val: an xmlNodePtr
2081 *
2082 * Removes an xmlNodePtr from an existing NodeSet
2083 */
2084void
2085xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2086 int i;
2087
2088 if (cur == NULL) return;
2089 if (val == NULL) return;
2090
2091 /*
William M. Brack08171912003-12-29 02:52:11 +00002092 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002093 */
2094 for (i = 0;i < cur->nodeNr;i++)
2095 if (cur->nodeTab[i] == val) break;
2096
William M. Brack08171912003-12-29 02:52:11 +00002097 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002098#ifdef DEBUG
2099 xmlGenericError(xmlGenericErrorContext,
2100 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2101 val->name);
2102#endif
2103 return;
2104 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002105 if ((cur->nodeTab[i] != NULL) &&
2106 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2107 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002108 cur->nodeNr--;
2109 for (;i < cur->nodeNr;i++)
2110 cur->nodeTab[i] = cur->nodeTab[i + 1];
2111 cur->nodeTab[cur->nodeNr] = NULL;
2112}
2113
2114/**
2115 * xmlXPathNodeSetRemove:
2116 * @cur: the initial node set
2117 * @val: the index to remove
2118 *
2119 * Removes an entry from an existing NodeSet list.
2120 */
2121void
2122xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2123 if (cur == NULL) return;
2124 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002125 if ((cur->nodeTab[val] != NULL) &&
2126 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2127 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002128 cur->nodeNr--;
2129 for (;val < cur->nodeNr;val++)
2130 cur->nodeTab[val] = cur->nodeTab[val + 1];
2131 cur->nodeTab[cur->nodeNr] = NULL;
2132}
2133
2134/**
2135 * xmlXPathFreeNodeSet:
2136 * @obj: the xmlNodeSetPtr to free
2137 *
2138 * Free the NodeSet compound (not the actual nodes !).
2139 */
2140void
2141xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2142 if (obj == NULL) return;
2143 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002144 int i;
2145
William M. Brack08171912003-12-29 02:52:11 +00002146 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002147 for (i = 0;i < obj->nodeNr;i++)
2148 if ((obj->nodeTab[i] != NULL) &&
2149 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2150 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
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/**
2157 * xmlXPathFreeValueTree:
2158 * @obj: the xmlNodeSetPtr to free
2159 *
2160 * Free the NodeSet compound and the actual tree, this is different
2161 * from xmlXPathFreeNodeSet()
2162 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002163static void
Owen Taylor3473f882001-02-23 17:55:21 +00002164xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2165 int i;
2166
2167 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002168
2169 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002170 for (i = 0;i < obj->nodeNr;i++) {
2171 if (obj->nodeTab[i] != NULL) {
2172 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2173 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2174 } else {
2175 xmlFreeNodeList(obj->nodeTab[i]);
2176 }
2177 }
2178 }
Owen Taylor3473f882001-02-23 17:55:21 +00002179 xmlFree(obj->nodeTab);
2180 }
Owen Taylor3473f882001-02-23 17:55:21 +00002181 xmlFree(obj);
2182}
2183
2184#if defined(DEBUG) || defined(DEBUG_STEP)
2185/**
2186 * xmlGenericErrorContextNodeSet:
2187 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002188 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002189 *
2190 * Quick display of a NodeSet
2191 */
2192void
2193xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2194 int i;
2195
2196 if (output == NULL) output = xmlGenericErrorContext;
2197 if (obj == NULL) {
2198 fprintf(output, "NodeSet == NULL !\n");
2199 return;
2200 }
2201 if (obj->nodeNr == 0) {
2202 fprintf(output, "NodeSet is empty\n");
2203 return;
2204 }
2205 if (obj->nodeTab == NULL) {
2206 fprintf(output, " nodeTab == NULL !\n");
2207 return;
2208 }
2209 for (i = 0; i < obj->nodeNr; i++) {
2210 if (obj->nodeTab[i] == NULL) {
2211 fprintf(output, " NULL !\n");
2212 return;
2213 }
2214 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2215 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2216 fprintf(output, " /");
2217 else if (obj->nodeTab[i]->name == NULL)
2218 fprintf(output, " noname!");
2219 else fprintf(output, " %s", obj->nodeTab[i]->name);
2220 }
2221 fprintf(output, "\n");
2222}
2223#endif
2224
2225/**
2226 * xmlXPathNewNodeSet:
2227 * @val: the NodePtr value
2228 *
2229 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2230 * it with the single Node @val
2231 *
2232 * Returns the newly created object.
2233 */
2234xmlXPathObjectPtr
2235xmlXPathNewNodeSet(xmlNodePtr val) {
2236 xmlXPathObjectPtr ret;
2237
2238 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2239 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002240 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002241 return(NULL);
2242 }
2243 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2244 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002245 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002246 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002247 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002248 return(ret);
2249}
2250
2251/**
2252 * xmlXPathNewValueTree:
2253 * @val: the NodePtr value
2254 *
2255 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2256 * it with the tree root @val
2257 *
2258 * Returns the newly created object.
2259 */
2260xmlXPathObjectPtr
2261xmlXPathNewValueTree(xmlNodePtr val) {
2262 xmlXPathObjectPtr ret;
2263
2264 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2265 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002266 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002267 return(NULL);
2268 }
2269 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2270 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002271 ret->boolval = 1;
2272 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002273 ret->nodesetval = xmlXPathNodeSetCreate(val);
2274 return(ret);
2275}
2276
2277/**
2278 * xmlXPathNewNodeSetList:
2279 * @val: an existing NodeSet
2280 *
2281 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2282 * it with the Nodeset @val
2283 *
2284 * Returns the newly created object.
2285 */
2286xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002287xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2288{
Owen Taylor3473f882001-02-23 17:55:21 +00002289 xmlXPathObjectPtr ret;
2290 int i;
2291
2292 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002293 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002294 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002295 ret = xmlXPathNewNodeSet(NULL);
2296 else {
2297 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2298 for (i = 1; i < val->nodeNr; ++i)
2299 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2300 }
Owen Taylor3473f882001-02-23 17:55:21 +00002301
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002302 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002303}
2304
2305/**
2306 * xmlXPathWrapNodeSet:
2307 * @val: the NodePtr value
2308 *
2309 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2310 *
2311 * Returns the newly created object.
2312 */
2313xmlXPathObjectPtr
2314xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2315 xmlXPathObjectPtr ret;
2316
2317 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2318 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002319 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002320 return(NULL);
2321 }
2322 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2323 ret->type = XPATH_NODESET;
2324 ret->nodesetval = val;
2325 return(ret);
2326}
2327
2328/**
2329 * xmlXPathFreeNodeSetList:
2330 * @obj: an existing NodeSetList object
2331 *
2332 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2333 * the list contrary to xmlXPathFreeObject().
2334 */
2335void
2336xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2337 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002338 xmlFree(obj);
2339}
2340
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002341/**
2342 * xmlXPathDifference:
2343 * @nodes1: a node-set
2344 * @nodes2: a node-set
2345 *
2346 * Implements the EXSLT - Sets difference() function:
2347 * node-set set:difference (node-set, node-set)
2348 *
2349 * Returns the difference between the two node sets, or nodes1 if
2350 * nodes2 is empty
2351 */
2352xmlNodeSetPtr
2353xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2354 xmlNodeSetPtr ret;
2355 int i, l1;
2356 xmlNodePtr cur;
2357
2358 if (xmlXPathNodeSetIsEmpty(nodes2))
2359 return(nodes1);
2360
2361 ret = xmlXPathNodeSetCreate(NULL);
2362 if (xmlXPathNodeSetIsEmpty(nodes1))
2363 return(ret);
2364
2365 l1 = xmlXPathNodeSetGetLength(nodes1);
2366
2367 for (i = 0; i < l1; i++) {
2368 cur = xmlXPathNodeSetItem(nodes1, i);
2369 if (!xmlXPathNodeSetContains(nodes2, cur))
2370 xmlXPathNodeSetAddUnique(ret, cur);
2371 }
2372 return(ret);
2373}
2374
2375/**
2376 * xmlXPathIntersection:
2377 * @nodes1: a node-set
2378 * @nodes2: a node-set
2379 *
2380 * Implements the EXSLT - Sets intersection() function:
2381 * node-set set:intersection (node-set, node-set)
2382 *
2383 * Returns a node set comprising the nodes that are within both the
2384 * node sets passed as arguments
2385 */
2386xmlNodeSetPtr
2387xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2388 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2389 int i, l1;
2390 xmlNodePtr cur;
2391
2392 if (xmlXPathNodeSetIsEmpty(nodes1))
2393 return(ret);
2394 if (xmlXPathNodeSetIsEmpty(nodes2))
2395 return(ret);
2396
2397 l1 = xmlXPathNodeSetGetLength(nodes1);
2398
2399 for (i = 0; i < l1; i++) {
2400 cur = xmlXPathNodeSetItem(nodes1, i);
2401 if (xmlXPathNodeSetContains(nodes2, cur))
2402 xmlXPathNodeSetAddUnique(ret, cur);
2403 }
2404 return(ret);
2405}
2406
2407/**
2408 * xmlXPathDistinctSorted:
2409 * @nodes: a node-set, sorted by document order
2410 *
2411 * Implements the EXSLT - Sets distinct() function:
2412 * node-set set:distinct (node-set)
2413 *
2414 * Returns a subset of the nodes contained in @nodes, or @nodes if
2415 * it is empty
2416 */
2417xmlNodeSetPtr
2418xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2419 xmlNodeSetPtr ret;
2420 xmlHashTablePtr hash;
2421 int i, l;
2422 xmlChar * strval;
2423 xmlNodePtr cur;
2424
2425 if (xmlXPathNodeSetIsEmpty(nodes))
2426 return(nodes);
2427
2428 ret = xmlXPathNodeSetCreate(NULL);
2429 l = xmlXPathNodeSetGetLength(nodes);
2430 hash = xmlHashCreate (l);
2431 for (i = 0; i < l; i++) {
2432 cur = xmlXPathNodeSetItem(nodes, i);
2433 strval = xmlXPathCastNodeToString(cur);
2434 if (xmlHashLookup(hash, strval) == NULL) {
2435 xmlHashAddEntry(hash, strval, strval);
2436 xmlXPathNodeSetAddUnique(ret, cur);
2437 } else {
2438 xmlFree(strval);
2439 }
2440 }
2441 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2442 return(ret);
2443}
2444
2445/**
2446 * xmlXPathDistinct:
2447 * @nodes: a node-set
2448 *
2449 * Implements the EXSLT - Sets distinct() function:
2450 * node-set set:distinct (node-set)
2451 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2452 * is called with the sorted node-set
2453 *
2454 * Returns a subset of the nodes contained in @nodes, or @nodes if
2455 * it is empty
2456 */
2457xmlNodeSetPtr
2458xmlXPathDistinct (xmlNodeSetPtr nodes) {
2459 if (xmlXPathNodeSetIsEmpty(nodes))
2460 return(nodes);
2461
2462 xmlXPathNodeSetSort(nodes);
2463 return(xmlXPathDistinctSorted(nodes));
2464}
2465
2466/**
2467 * xmlXPathHasSameNodes:
2468 * @nodes1: a node-set
2469 * @nodes2: a node-set
2470 *
2471 * Implements the EXSLT - Sets has-same-nodes function:
2472 * boolean set:has-same-node(node-set, node-set)
2473 *
2474 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2475 * otherwise
2476 */
2477int
2478xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2479 int i, l;
2480 xmlNodePtr cur;
2481
2482 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2483 xmlXPathNodeSetIsEmpty(nodes2))
2484 return(0);
2485
2486 l = xmlXPathNodeSetGetLength(nodes1);
2487 for (i = 0; i < l; i++) {
2488 cur = xmlXPathNodeSetItem(nodes1, i);
2489 if (xmlXPathNodeSetContains(nodes2, cur))
2490 return(1);
2491 }
2492 return(0);
2493}
2494
2495/**
2496 * xmlXPathNodeLeadingSorted:
2497 * @nodes: a node-set, sorted by document order
2498 * @node: a node
2499 *
2500 * Implements the EXSLT - Sets leading() function:
2501 * node-set set:leading (node-set, node-set)
2502 *
2503 * Returns the nodes in @nodes that precede @node in document order,
2504 * @nodes if @node is NULL or an empty node-set if @nodes
2505 * doesn't contain @node
2506 */
2507xmlNodeSetPtr
2508xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2509 int i, l;
2510 xmlNodePtr cur;
2511 xmlNodeSetPtr ret;
2512
2513 if (node == NULL)
2514 return(nodes);
2515
2516 ret = xmlXPathNodeSetCreate(NULL);
2517 if (xmlXPathNodeSetIsEmpty(nodes) ||
2518 (!xmlXPathNodeSetContains(nodes, node)))
2519 return(ret);
2520
2521 l = xmlXPathNodeSetGetLength(nodes);
2522 for (i = 0; i < l; i++) {
2523 cur = xmlXPathNodeSetItem(nodes, i);
2524 if (cur == node)
2525 break;
2526 xmlXPathNodeSetAddUnique(ret, cur);
2527 }
2528 return(ret);
2529}
2530
2531/**
2532 * xmlXPathNodeLeading:
2533 * @nodes: a node-set
2534 * @node: a node
2535 *
2536 * Implements the EXSLT - Sets leading() function:
2537 * node-set set:leading (node-set, node-set)
2538 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2539 * is called.
2540 *
2541 * Returns the nodes in @nodes that precede @node in document order,
2542 * @nodes if @node is NULL or an empty node-set if @nodes
2543 * doesn't contain @node
2544 */
2545xmlNodeSetPtr
2546xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2547 xmlXPathNodeSetSort(nodes);
2548 return(xmlXPathNodeLeadingSorted(nodes, node));
2549}
2550
2551/**
2552 * xmlXPathLeadingSorted:
2553 * @nodes1: a node-set, sorted by document order
2554 * @nodes2: a node-set, sorted by document order
2555 *
2556 * Implements the EXSLT - Sets leading() function:
2557 * node-set set:leading (node-set, node-set)
2558 *
2559 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2560 * in document order, @nodes1 if @nodes2 is NULL or empty or
2561 * an empty node-set if @nodes1 doesn't contain @nodes2
2562 */
2563xmlNodeSetPtr
2564xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2565 if (xmlXPathNodeSetIsEmpty(nodes2))
2566 return(nodes1);
2567 return(xmlXPathNodeLeadingSorted(nodes1,
2568 xmlXPathNodeSetItem(nodes2, 1)));
2569}
2570
2571/**
2572 * xmlXPathLeading:
2573 * @nodes1: a node-set
2574 * @nodes2: a node-set
2575 *
2576 * Implements the EXSLT - Sets leading() function:
2577 * node-set set:leading (node-set, node-set)
2578 * @nodes1 and @nodes2 are sorted by document order, then
2579 * #exslSetsLeadingSorted is called.
2580 *
2581 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2582 * in document order, @nodes1 if @nodes2 is NULL or empty or
2583 * an empty node-set if @nodes1 doesn't contain @nodes2
2584 */
2585xmlNodeSetPtr
2586xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2587 if (xmlXPathNodeSetIsEmpty(nodes2))
2588 return(nodes1);
2589 if (xmlXPathNodeSetIsEmpty(nodes1))
2590 return(xmlXPathNodeSetCreate(NULL));
2591 xmlXPathNodeSetSort(nodes1);
2592 xmlXPathNodeSetSort(nodes2);
2593 return(xmlXPathNodeLeadingSorted(nodes1,
2594 xmlXPathNodeSetItem(nodes2, 1)));
2595}
2596
2597/**
2598 * xmlXPathNodeTrailingSorted:
2599 * @nodes: a node-set, sorted by document order
2600 * @node: a node
2601 *
2602 * Implements the EXSLT - Sets trailing() function:
2603 * node-set set:trailing (node-set, node-set)
2604 *
2605 * Returns the nodes in @nodes that follow @node in document order,
2606 * @nodes if @node is NULL or an empty node-set if @nodes
2607 * doesn't contain @node
2608 */
2609xmlNodeSetPtr
2610xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2611 int i, l;
2612 xmlNodePtr cur;
2613 xmlNodeSetPtr ret;
2614
2615 if (node == NULL)
2616 return(nodes);
2617
2618 ret = xmlXPathNodeSetCreate(NULL);
2619 if (xmlXPathNodeSetIsEmpty(nodes) ||
2620 (!xmlXPathNodeSetContains(nodes, node)))
2621 return(ret);
2622
2623 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002624 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002625 cur = xmlXPathNodeSetItem(nodes, i);
2626 if (cur == node)
2627 break;
2628 xmlXPathNodeSetAddUnique(ret, cur);
2629 }
2630 return(ret);
2631}
2632
2633/**
2634 * xmlXPathNodeTrailing:
2635 * @nodes: a node-set
2636 * @node: a node
2637 *
2638 * Implements the EXSLT - Sets trailing() function:
2639 * node-set set:trailing (node-set, node-set)
2640 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2641 * is called.
2642 *
2643 * Returns the nodes in @nodes that follow @node in document order,
2644 * @nodes if @node is NULL or an empty node-set if @nodes
2645 * doesn't contain @node
2646 */
2647xmlNodeSetPtr
2648xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2649 xmlXPathNodeSetSort(nodes);
2650 return(xmlXPathNodeTrailingSorted(nodes, node));
2651}
2652
2653/**
2654 * xmlXPathTrailingSorted:
2655 * @nodes1: a node-set, sorted by document order
2656 * @nodes2: a node-set, sorted by document order
2657 *
2658 * Implements the EXSLT - Sets trailing() function:
2659 * node-set set:trailing (node-set, node-set)
2660 *
2661 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2662 * in document order, @nodes1 if @nodes2 is NULL or empty or
2663 * an empty node-set if @nodes1 doesn't contain @nodes2
2664 */
2665xmlNodeSetPtr
2666xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2667 if (xmlXPathNodeSetIsEmpty(nodes2))
2668 return(nodes1);
2669 return(xmlXPathNodeTrailingSorted(nodes1,
2670 xmlXPathNodeSetItem(nodes2, 0)));
2671}
2672
2673/**
2674 * xmlXPathTrailing:
2675 * @nodes1: a node-set
2676 * @nodes2: a node-set
2677 *
2678 * Implements the EXSLT - Sets trailing() function:
2679 * node-set set:trailing (node-set, node-set)
2680 * @nodes1 and @nodes2 are sorted by document order, then
2681 * #xmlXPathTrailingSorted is called.
2682 *
2683 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2684 * in document order, @nodes1 if @nodes2 is NULL or empty or
2685 * an empty node-set if @nodes1 doesn't contain @nodes2
2686 */
2687xmlNodeSetPtr
2688xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2689 if (xmlXPathNodeSetIsEmpty(nodes2))
2690 return(nodes1);
2691 if (xmlXPathNodeSetIsEmpty(nodes1))
2692 return(xmlXPathNodeSetCreate(NULL));
2693 xmlXPathNodeSetSort(nodes1);
2694 xmlXPathNodeSetSort(nodes2);
2695 return(xmlXPathNodeTrailingSorted(nodes1,
2696 xmlXPathNodeSetItem(nodes2, 0)));
2697}
2698
Owen Taylor3473f882001-02-23 17:55:21 +00002699/************************************************************************
2700 * *
2701 * Routines to handle extra functions *
2702 * *
2703 ************************************************************************/
2704
2705/**
2706 * xmlXPathRegisterFunc:
2707 * @ctxt: the XPath context
2708 * @name: the function name
2709 * @f: the function implementation or NULL
2710 *
2711 * Register a new function. If @f is NULL it unregisters the function
2712 *
2713 * Returns 0 in case of success, -1 in case of error
2714 */
2715int
2716xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2717 xmlXPathFunction f) {
2718 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2719}
2720
2721/**
2722 * xmlXPathRegisterFuncNS:
2723 * @ctxt: the XPath context
2724 * @name: the function name
2725 * @ns_uri: the function namespace URI
2726 * @f: the function implementation or NULL
2727 *
2728 * Register a new function. If @f is NULL it unregisters the function
2729 *
2730 * Returns 0 in case of success, -1 in case of error
2731 */
2732int
2733xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2734 const xmlChar *ns_uri, xmlXPathFunction f) {
2735 if (ctxt == NULL)
2736 return(-1);
2737 if (name == NULL)
2738 return(-1);
2739
2740 if (ctxt->funcHash == NULL)
2741 ctxt->funcHash = xmlHashCreate(0);
2742 if (ctxt->funcHash == NULL)
2743 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002744 if (f == NULL)
2745 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
Owen Taylor3473f882001-02-23 17:55:21 +00002746 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2747}
2748
2749/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002750 * xmlXPathRegisterFuncLookup:
2751 * @ctxt: the XPath context
2752 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002753 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002754 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002755 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002756 */
2757void
2758xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2759 xmlXPathFuncLookupFunc f,
2760 void *funcCtxt) {
2761 if (ctxt == NULL)
2762 return;
2763 ctxt->funcLookupFunc = (void *) f;
2764 ctxt->funcLookupData = funcCtxt;
2765}
2766
2767/**
Owen Taylor3473f882001-02-23 17:55:21 +00002768 * xmlXPathFunctionLookup:
2769 * @ctxt: the XPath context
2770 * @name: the function name
2771 *
2772 * Search in the Function array of the context for the given
2773 * function.
2774 *
2775 * Returns the xmlXPathFunction or NULL if not found
2776 */
2777xmlXPathFunction
2778xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002779 if (ctxt == NULL)
2780 return (NULL);
2781
2782 if (ctxt->funcLookupFunc != NULL) {
2783 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002784 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002785
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002786 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002787 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002788 if (ret != NULL)
2789 return(ret);
2790 }
Owen Taylor3473f882001-02-23 17:55:21 +00002791 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2792}
2793
2794/**
2795 * xmlXPathFunctionLookupNS:
2796 * @ctxt: the XPath context
2797 * @name: the function name
2798 * @ns_uri: the function namespace URI
2799 *
2800 * Search in the Function array of the context for the given
2801 * function.
2802 *
2803 * Returns the xmlXPathFunction or NULL if not found
2804 */
2805xmlXPathFunction
2806xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2807 const xmlChar *ns_uri) {
2808 if (ctxt == NULL)
2809 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002810 if (name == NULL)
2811 return(NULL);
2812
Thomas Broyerba4ad322001-07-26 16:55:21 +00002813 if (ctxt->funcLookupFunc != NULL) {
2814 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002815 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002816
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002817 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002818 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002819 if (ret != NULL)
2820 return(ret);
2821 }
2822
2823 if (ctxt->funcHash == NULL)
2824 return(NULL);
2825
Owen Taylor3473f882001-02-23 17:55:21 +00002826 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2827}
2828
2829/**
2830 * xmlXPathRegisteredFuncsCleanup:
2831 * @ctxt: the XPath context
2832 *
2833 * Cleanup the XPath context data associated to registered functions
2834 */
2835void
2836xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2837 if (ctxt == NULL)
2838 return;
2839
2840 xmlHashFree(ctxt->funcHash, NULL);
2841 ctxt->funcHash = NULL;
2842}
2843
2844/************************************************************************
2845 * *
William M. Brack08171912003-12-29 02:52:11 +00002846 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00002847 * *
2848 ************************************************************************/
2849
2850/**
2851 * xmlXPathRegisterVariable:
2852 * @ctxt: the XPath context
2853 * @name: the variable name
2854 * @value: the variable value or NULL
2855 *
2856 * Register a new variable value. If @value is NULL it unregisters
2857 * the variable
2858 *
2859 * Returns 0 in case of success, -1 in case of error
2860 */
2861int
2862xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2863 xmlXPathObjectPtr value) {
2864 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2865}
2866
2867/**
2868 * xmlXPathRegisterVariableNS:
2869 * @ctxt: the XPath context
2870 * @name: the variable name
2871 * @ns_uri: the variable namespace URI
2872 * @value: the variable value or NULL
2873 *
2874 * Register a new variable value. If @value is NULL it unregisters
2875 * the variable
2876 *
2877 * Returns 0 in case of success, -1 in case of error
2878 */
2879int
2880xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2881 const xmlChar *ns_uri,
2882 xmlXPathObjectPtr value) {
2883 if (ctxt == NULL)
2884 return(-1);
2885 if (name == NULL)
2886 return(-1);
2887
2888 if (ctxt->varHash == NULL)
2889 ctxt->varHash = xmlHashCreate(0);
2890 if (ctxt->varHash == NULL)
2891 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002892 if (value == NULL)
2893 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2894 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002895 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2896 (void *) value,
2897 (xmlHashDeallocator)xmlXPathFreeObject));
2898}
2899
2900/**
2901 * xmlXPathRegisterVariableLookup:
2902 * @ctxt: the XPath context
2903 * @f: the lookup function
2904 * @data: the lookup data
2905 *
2906 * register an external mechanism to do variable lookup
2907 */
2908void
2909xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2910 xmlXPathVariableLookupFunc f, void *data) {
2911 if (ctxt == NULL)
2912 return;
2913 ctxt->varLookupFunc = (void *) f;
2914 ctxt->varLookupData = data;
2915}
2916
2917/**
2918 * xmlXPathVariableLookup:
2919 * @ctxt: the XPath context
2920 * @name: the variable name
2921 *
2922 * Search in the Variable array of the context for the given
2923 * variable value.
2924 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002925 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002926 */
2927xmlXPathObjectPtr
2928xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2929 if (ctxt == NULL)
2930 return(NULL);
2931
2932 if (ctxt->varLookupFunc != NULL) {
2933 xmlXPathObjectPtr ret;
2934
2935 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2936 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002937 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002938 }
2939 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2940}
2941
2942/**
2943 * xmlXPathVariableLookupNS:
2944 * @ctxt: the XPath context
2945 * @name: the variable name
2946 * @ns_uri: the variable namespace URI
2947 *
2948 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00002949 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00002950 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002951 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002952 */
2953xmlXPathObjectPtr
2954xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2955 const xmlChar *ns_uri) {
2956 if (ctxt == NULL)
2957 return(NULL);
2958
2959 if (ctxt->varLookupFunc != NULL) {
2960 xmlXPathObjectPtr ret;
2961
2962 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2963 (ctxt->varLookupData, name, ns_uri);
2964 if (ret != NULL) return(ret);
2965 }
2966
2967 if (ctxt->varHash == NULL)
2968 return(NULL);
2969 if (name == NULL)
2970 return(NULL);
2971
Daniel Veillard8c357d52001-07-03 23:43:33 +00002972 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2973 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00002974}
2975
2976/**
2977 * xmlXPathRegisteredVariablesCleanup:
2978 * @ctxt: the XPath context
2979 *
2980 * Cleanup the XPath context data associated to registered variables
2981 */
2982void
2983xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2984 if (ctxt == NULL)
2985 return;
2986
Daniel Veillard76d66f42001-05-16 21:05:17 +00002987 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00002988 ctxt->varHash = NULL;
2989}
2990
2991/**
2992 * xmlXPathRegisterNs:
2993 * @ctxt: the XPath context
2994 * @prefix: the namespace prefix
2995 * @ns_uri: the namespace name
2996 *
2997 * Register a new namespace. If @ns_uri is NULL it unregisters
2998 * the namespace
2999 *
3000 * Returns 0 in case of success, -1 in case of error
3001 */
3002int
3003xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3004 const xmlChar *ns_uri) {
3005 if (ctxt == NULL)
3006 return(-1);
3007 if (prefix == NULL)
3008 return(-1);
3009
3010 if (ctxt->nsHash == NULL)
3011 ctxt->nsHash = xmlHashCreate(10);
3012 if (ctxt->nsHash == NULL)
3013 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003014 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003015 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003016 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003017 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003018 (xmlHashDeallocator)xmlFree));
3019}
3020
3021/**
3022 * xmlXPathNsLookup:
3023 * @ctxt: the XPath context
3024 * @prefix: the namespace prefix value
3025 *
3026 * Search in the namespace declaration array of the context for the given
3027 * namespace name associated to the given prefix
3028 *
3029 * Returns the value or NULL if not found
3030 */
3031const xmlChar *
3032xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3033 if (ctxt == NULL)
3034 return(NULL);
3035 if (prefix == NULL)
3036 return(NULL);
3037
3038#ifdef XML_XML_NAMESPACE
3039 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3040 return(XML_XML_NAMESPACE);
3041#endif
3042
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003043 if (ctxt->namespaces != NULL) {
3044 int i;
3045
3046 for (i = 0;i < ctxt->nsNr;i++) {
3047 if ((ctxt->namespaces[i] != NULL) &&
3048 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3049 return(ctxt->namespaces[i]->href);
3050 }
3051 }
Owen Taylor3473f882001-02-23 17:55:21 +00003052
3053 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3054}
3055
3056/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003057 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003058 * @ctxt: the XPath context
3059 *
3060 * Cleanup the XPath context data associated to registered variables
3061 */
3062void
3063xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3064 if (ctxt == NULL)
3065 return;
3066
Daniel Veillard42766c02002-08-22 20:52:17 +00003067 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003068 ctxt->nsHash = NULL;
3069}
3070
3071/************************************************************************
3072 * *
3073 * Routines to handle Values *
3074 * *
3075 ************************************************************************/
3076
William M. Brack08171912003-12-29 02:52:11 +00003077/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003078
3079/**
3080 * xmlXPathNewFloat:
3081 * @val: the double value
3082 *
3083 * Create a new xmlXPathObjectPtr of type double and of value @val
3084 *
3085 * Returns the newly created object.
3086 */
3087xmlXPathObjectPtr
3088xmlXPathNewFloat(double val) {
3089 xmlXPathObjectPtr ret;
3090
3091 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3092 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003093 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003094 return(NULL);
3095 }
3096 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3097 ret->type = XPATH_NUMBER;
3098 ret->floatval = val;
3099 return(ret);
3100}
3101
3102/**
3103 * xmlXPathNewBoolean:
3104 * @val: the boolean value
3105 *
3106 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3107 *
3108 * Returns the newly created object.
3109 */
3110xmlXPathObjectPtr
3111xmlXPathNewBoolean(int val) {
3112 xmlXPathObjectPtr ret;
3113
3114 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3115 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003116 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003117 return(NULL);
3118 }
3119 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3120 ret->type = XPATH_BOOLEAN;
3121 ret->boolval = (val != 0);
3122 return(ret);
3123}
3124
3125/**
3126 * xmlXPathNewString:
3127 * @val: the xmlChar * value
3128 *
3129 * Create a new xmlXPathObjectPtr of type string and of value @val
3130 *
3131 * Returns the newly created object.
3132 */
3133xmlXPathObjectPtr
3134xmlXPathNewString(const xmlChar *val) {
3135 xmlXPathObjectPtr ret;
3136
3137 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3138 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003139 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003140 return(NULL);
3141 }
3142 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3143 ret->type = XPATH_STRING;
3144 if (val != NULL)
3145 ret->stringval = xmlStrdup(val);
3146 else
3147 ret->stringval = xmlStrdup((const xmlChar *)"");
3148 return(ret);
3149}
3150
3151/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003152 * xmlXPathWrapString:
3153 * @val: the xmlChar * value
3154 *
3155 * Wraps the @val string into an XPath object.
3156 *
3157 * Returns the newly created object.
3158 */
3159xmlXPathObjectPtr
3160xmlXPathWrapString (xmlChar *val) {
3161 xmlXPathObjectPtr ret;
3162
3163 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3164 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003165 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003166 return(NULL);
3167 }
3168 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3169 ret->type = XPATH_STRING;
3170 ret->stringval = val;
3171 return(ret);
3172}
3173
3174/**
Owen Taylor3473f882001-02-23 17:55:21 +00003175 * xmlXPathNewCString:
3176 * @val: the char * value
3177 *
3178 * Create a new xmlXPathObjectPtr of type string and of value @val
3179 *
3180 * Returns the newly created object.
3181 */
3182xmlXPathObjectPtr
3183xmlXPathNewCString(const char *val) {
3184 xmlXPathObjectPtr ret;
3185
3186 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3187 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003188 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003189 return(NULL);
3190 }
3191 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3192 ret->type = XPATH_STRING;
3193 ret->stringval = xmlStrdup(BAD_CAST val);
3194 return(ret);
3195}
3196
3197/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003198 * xmlXPathWrapCString:
3199 * @val: the char * value
3200 *
3201 * Wraps a string into an XPath object.
3202 *
3203 * Returns the newly created object.
3204 */
3205xmlXPathObjectPtr
3206xmlXPathWrapCString (char * val) {
3207 return(xmlXPathWrapString((xmlChar *)(val)));
3208}
3209
3210/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003211 * xmlXPathWrapExternal:
3212 * @val: the user data
3213 *
3214 * Wraps the @val data into an XPath object.
3215 *
3216 * Returns the newly created object.
3217 */
3218xmlXPathObjectPtr
3219xmlXPathWrapExternal (void *val) {
3220 xmlXPathObjectPtr ret;
3221
3222 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3223 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003224 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003225 return(NULL);
3226 }
3227 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3228 ret->type = XPATH_USERS;
3229 ret->user = val;
3230 return(ret);
3231}
3232
3233/**
Owen Taylor3473f882001-02-23 17:55:21 +00003234 * xmlXPathObjectCopy:
3235 * @val: the original object
3236 *
3237 * allocate a new copy of a given object
3238 *
3239 * Returns the newly created object.
3240 */
3241xmlXPathObjectPtr
3242xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3243 xmlXPathObjectPtr ret;
3244
3245 if (val == NULL)
3246 return(NULL);
3247
3248 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3249 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003250 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003251 return(NULL);
3252 }
3253 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3254 switch (val->type) {
3255 case XPATH_BOOLEAN:
3256 case XPATH_NUMBER:
3257 case XPATH_POINT:
3258 case XPATH_RANGE:
3259 break;
3260 case XPATH_STRING:
3261 ret->stringval = xmlStrdup(val->stringval);
3262 break;
3263 case XPATH_XSLT_TREE:
3264 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003265 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003266 xmlNodePtr cur, tmp;
3267 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003268
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003269 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003270 top = xmlNewDoc(NULL);
3271 top->name = (char *)
3272 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003273 ret->user = top;
3274 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003275 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003276 cur = val->nodesetval->nodeTab[0]->children;
3277 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003278 tmp = xmlDocCopyNode(cur, top, 1);
3279 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003280 cur = cur->next;
3281 }
3282 }
Daniel Veillard9adc0462003-03-24 18:39:54 +00003283 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003284 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003285 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003286 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003287 break;
3288 case XPATH_NODESET:
3289 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003290 /* Do not deallocate the copied tree value */
3291 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003292 break;
3293 case XPATH_LOCATIONSET:
3294#ifdef LIBXML_XPTR_ENABLED
3295 {
3296 xmlLocationSetPtr loc = val->user;
3297 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3298 break;
3299 }
3300#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003301 case XPATH_USERS:
3302 ret->user = val->user;
3303 break;
3304 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003305 xmlGenericError(xmlGenericErrorContext,
3306 "xmlXPathObjectCopy: unsupported type %d\n",
3307 val->type);
3308 break;
3309 }
3310 return(ret);
3311}
3312
3313/**
3314 * xmlXPathFreeObject:
3315 * @obj: the object to free
3316 *
3317 * Free up an xmlXPathObjectPtr object.
3318 */
3319void
3320xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3321 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003322 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003323 if (obj->boolval) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003324 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003325 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003326 xmlFreeNodeList((xmlNodePtr) obj->user);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003327 } else if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003328 xmlXPathFreeValueTree(obj->nodesetval);
3329 } else {
3330 if (obj->nodesetval != NULL)
3331 xmlXPathFreeNodeSet(obj->nodesetval);
3332 }
Owen Taylor3473f882001-02-23 17:55:21 +00003333#ifdef LIBXML_XPTR_ENABLED
3334 } else if (obj->type == XPATH_LOCATIONSET) {
3335 if (obj->user != NULL)
3336 xmlXPtrFreeLocationSet(obj->user);
3337#endif
3338 } else if (obj->type == XPATH_STRING) {
3339 if (obj->stringval != NULL)
3340 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003341 }
3342
Owen Taylor3473f882001-02-23 17:55:21 +00003343 xmlFree(obj);
3344}
3345
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003346
3347/************************************************************************
3348 * *
3349 * Type Casting Routines *
3350 * *
3351 ************************************************************************/
3352
3353/**
3354 * xmlXPathCastBooleanToString:
3355 * @val: a boolean
3356 *
3357 * Converts a boolean to its string value.
3358 *
3359 * Returns a newly allocated string.
3360 */
3361xmlChar *
3362xmlXPathCastBooleanToString (int val) {
3363 xmlChar *ret;
3364 if (val)
3365 ret = xmlStrdup((const xmlChar *) "true");
3366 else
3367 ret = xmlStrdup((const xmlChar *) "false");
3368 return(ret);
3369}
3370
3371/**
3372 * xmlXPathCastNumberToString:
3373 * @val: a number
3374 *
3375 * Converts a number to its string value.
3376 *
3377 * Returns a newly allocated string.
3378 */
3379xmlChar *
3380xmlXPathCastNumberToString (double val) {
3381 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003382 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003383 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003384 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003385 break;
3386 case -1:
3387 ret = xmlStrdup((const xmlChar *) "-Infinity");
3388 break;
3389 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003390 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003391 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003392 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3393 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003394 } else {
3395 /* could be improved */
3396 char buf[100];
3397 xmlXPathFormatNumber(val, buf, 100);
3398 ret = xmlStrdup((const xmlChar *) buf);
3399 }
3400 }
3401 return(ret);
3402}
3403
3404/**
3405 * xmlXPathCastNodeToString:
3406 * @node: a node
3407 *
3408 * Converts a node to its string value.
3409 *
3410 * Returns a newly allocated string.
3411 */
3412xmlChar *
3413xmlXPathCastNodeToString (xmlNodePtr node) {
3414 return(xmlNodeGetContent(node));
3415}
3416
3417/**
3418 * xmlXPathCastNodeSetToString:
3419 * @ns: a node-set
3420 *
3421 * Converts a node-set to its string value.
3422 *
3423 * Returns a newly allocated string.
3424 */
3425xmlChar *
3426xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3427 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3428 return(xmlStrdup((const xmlChar *) ""));
3429
3430 xmlXPathNodeSetSort(ns);
3431 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3432}
3433
3434/**
3435 * xmlXPathCastToString:
3436 * @val: an XPath object
3437 *
3438 * Converts an existing object to its string() equivalent
3439 *
3440 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003441 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003442 * string object).
3443 */
3444xmlChar *
3445xmlXPathCastToString(xmlXPathObjectPtr val) {
3446 xmlChar *ret = NULL;
3447
3448 if (val == NULL)
3449 return(xmlStrdup((const xmlChar *) ""));
3450 switch (val->type) {
3451 case XPATH_UNDEFINED:
3452#ifdef DEBUG_EXPR
3453 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3454#endif
3455 ret = xmlStrdup((const xmlChar *) "");
3456 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003457 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003458 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003459 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3460 break;
3461 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003462 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003463 case XPATH_BOOLEAN:
3464 ret = xmlXPathCastBooleanToString(val->boolval);
3465 break;
3466 case XPATH_NUMBER: {
3467 ret = xmlXPathCastNumberToString(val->floatval);
3468 break;
3469 }
3470 case XPATH_USERS:
3471 case XPATH_POINT:
3472 case XPATH_RANGE:
3473 case XPATH_LOCATIONSET:
3474 TODO
3475 ret = xmlStrdup((const xmlChar *) "");
3476 break;
3477 }
3478 return(ret);
3479}
3480
3481/**
3482 * xmlXPathConvertString:
3483 * @val: an XPath object
3484 *
3485 * Converts an existing object to its string() equivalent
3486 *
3487 * Returns the new object, the old one is freed (or the operation
3488 * is done directly on @val)
3489 */
3490xmlXPathObjectPtr
3491xmlXPathConvertString(xmlXPathObjectPtr val) {
3492 xmlChar *res = NULL;
3493
3494 if (val == NULL)
3495 return(xmlXPathNewCString(""));
3496
3497 switch (val->type) {
3498 case XPATH_UNDEFINED:
3499#ifdef DEBUG_EXPR
3500 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3501#endif
3502 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003503 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003504 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003505 res = xmlXPathCastNodeSetToString(val->nodesetval);
3506 break;
3507 case XPATH_STRING:
3508 return(val);
3509 case XPATH_BOOLEAN:
3510 res = xmlXPathCastBooleanToString(val->boolval);
3511 break;
3512 case XPATH_NUMBER:
3513 res = xmlXPathCastNumberToString(val->floatval);
3514 break;
3515 case XPATH_USERS:
3516 case XPATH_POINT:
3517 case XPATH_RANGE:
3518 case XPATH_LOCATIONSET:
3519 TODO;
3520 break;
3521 }
3522 xmlXPathFreeObject(val);
3523 if (res == NULL)
3524 return(xmlXPathNewCString(""));
3525 return(xmlXPathWrapString(res));
3526}
3527
3528/**
3529 * xmlXPathCastBooleanToNumber:
3530 * @val: a boolean
3531 *
3532 * Converts a boolean to its number value
3533 *
3534 * Returns the number value
3535 */
3536double
3537xmlXPathCastBooleanToNumber(int val) {
3538 if (val)
3539 return(1.0);
3540 return(0.0);
3541}
3542
3543/**
3544 * xmlXPathCastStringToNumber:
3545 * @val: a string
3546 *
3547 * Converts a string to its number value
3548 *
3549 * Returns the number value
3550 */
3551double
3552xmlXPathCastStringToNumber(const xmlChar * val) {
3553 return(xmlXPathStringEvalNumber(val));
3554}
3555
3556/**
3557 * xmlXPathCastNodeToNumber:
3558 * @node: a node
3559 *
3560 * Converts a node to its number value
3561 *
3562 * Returns the number value
3563 */
3564double
3565xmlXPathCastNodeToNumber (xmlNodePtr node) {
3566 xmlChar *strval;
3567 double ret;
3568
3569 if (node == NULL)
3570 return(xmlXPathNAN);
3571 strval = xmlXPathCastNodeToString(node);
3572 if (strval == NULL)
3573 return(xmlXPathNAN);
3574 ret = xmlXPathCastStringToNumber(strval);
3575 xmlFree(strval);
3576
3577 return(ret);
3578}
3579
3580/**
3581 * xmlXPathCastNodeSetToNumber:
3582 * @ns: a node-set
3583 *
3584 * Converts a node-set to its number value
3585 *
3586 * Returns the number value
3587 */
3588double
3589xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3590 xmlChar *str;
3591 double ret;
3592
3593 if (ns == NULL)
3594 return(xmlXPathNAN);
3595 str = xmlXPathCastNodeSetToString(ns);
3596 ret = xmlXPathCastStringToNumber(str);
3597 xmlFree(str);
3598 return(ret);
3599}
3600
3601/**
3602 * xmlXPathCastToNumber:
3603 * @val: an XPath object
3604 *
3605 * Converts an XPath object to its number value
3606 *
3607 * Returns the number value
3608 */
3609double
3610xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3611 double ret = 0.0;
3612
3613 if (val == NULL)
3614 return(xmlXPathNAN);
3615 switch (val->type) {
3616 case XPATH_UNDEFINED:
3617#ifdef DEGUB_EXPR
3618 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3619#endif
3620 ret = xmlXPathNAN;
3621 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003622 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003623 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003624 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3625 break;
3626 case XPATH_STRING:
3627 ret = xmlXPathCastStringToNumber(val->stringval);
3628 break;
3629 case XPATH_NUMBER:
3630 ret = val->floatval;
3631 break;
3632 case XPATH_BOOLEAN:
3633 ret = xmlXPathCastBooleanToNumber(val->boolval);
3634 break;
3635 case XPATH_USERS:
3636 case XPATH_POINT:
3637 case XPATH_RANGE:
3638 case XPATH_LOCATIONSET:
3639 TODO;
3640 ret = xmlXPathNAN;
3641 break;
3642 }
3643 return(ret);
3644}
3645
3646/**
3647 * xmlXPathConvertNumber:
3648 * @val: an XPath object
3649 *
3650 * Converts an existing object to its number() equivalent
3651 *
3652 * Returns the new object, the old one is freed (or the operation
3653 * is done directly on @val)
3654 */
3655xmlXPathObjectPtr
3656xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3657 xmlXPathObjectPtr ret;
3658
3659 if (val == NULL)
3660 return(xmlXPathNewFloat(0.0));
3661 if (val->type == XPATH_NUMBER)
3662 return(val);
3663 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3664 xmlXPathFreeObject(val);
3665 return(ret);
3666}
3667
3668/**
3669 * xmlXPathCastNumberToBoolean:
3670 * @val: a number
3671 *
3672 * Converts a number to its boolean value
3673 *
3674 * Returns the boolean value
3675 */
3676int
3677xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003678 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003679 return(0);
3680 return(1);
3681}
3682
3683/**
3684 * xmlXPathCastStringToBoolean:
3685 * @val: a string
3686 *
3687 * Converts a string to its boolean value
3688 *
3689 * Returns the boolean value
3690 */
3691int
3692xmlXPathCastStringToBoolean (const xmlChar *val) {
3693 if ((val == NULL) || (xmlStrlen(val) == 0))
3694 return(0);
3695 return(1);
3696}
3697
3698/**
3699 * xmlXPathCastNodeSetToBoolean:
3700 * @ns: a node-set
3701 *
3702 * Converts a node-set to its boolean value
3703 *
3704 * Returns the boolean value
3705 */
3706int
3707xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3708 if ((ns == NULL) || (ns->nodeNr == 0))
3709 return(0);
3710 return(1);
3711}
3712
3713/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003714 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003715 * @val: an XPath object
3716 *
3717 * Converts an XPath object to its boolean value
3718 *
3719 * Returns the boolean value
3720 */
3721int
3722xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3723 int ret = 0;
3724
3725 if (val == NULL)
3726 return(0);
3727 switch (val->type) {
3728 case XPATH_UNDEFINED:
3729#ifdef DEBUG_EXPR
3730 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3731#endif
3732 ret = 0;
3733 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003734 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003735 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003736 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3737 break;
3738 case XPATH_STRING:
3739 ret = xmlXPathCastStringToBoolean(val->stringval);
3740 break;
3741 case XPATH_NUMBER:
3742 ret = xmlXPathCastNumberToBoolean(val->floatval);
3743 break;
3744 case XPATH_BOOLEAN:
3745 ret = val->boolval;
3746 break;
3747 case XPATH_USERS:
3748 case XPATH_POINT:
3749 case XPATH_RANGE:
3750 case XPATH_LOCATIONSET:
3751 TODO;
3752 ret = 0;
3753 break;
3754 }
3755 return(ret);
3756}
3757
3758
3759/**
3760 * xmlXPathConvertBoolean:
3761 * @val: an XPath object
3762 *
3763 * Converts an existing object to its boolean() equivalent
3764 *
3765 * Returns the new object, the old one is freed (or the operation
3766 * is done directly on @val)
3767 */
3768xmlXPathObjectPtr
3769xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3770 xmlXPathObjectPtr ret;
3771
3772 if (val == NULL)
3773 return(xmlXPathNewBoolean(0));
3774 if (val->type == XPATH_BOOLEAN)
3775 return(val);
3776 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3777 xmlXPathFreeObject(val);
3778 return(ret);
3779}
3780
Owen Taylor3473f882001-02-23 17:55:21 +00003781/************************************************************************
3782 * *
3783 * Routines to handle XPath contexts *
3784 * *
3785 ************************************************************************/
3786
3787/**
3788 * xmlXPathNewContext:
3789 * @doc: the XML document
3790 *
3791 * Create a new xmlXPathContext
3792 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003793 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003794 */
3795xmlXPathContextPtr
3796xmlXPathNewContext(xmlDocPtr doc) {
3797 xmlXPathContextPtr ret;
3798
3799 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3800 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003801 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003802 return(NULL);
3803 }
3804 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3805 ret->doc = doc;
3806 ret->node = NULL;
3807
3808 ret->varHash = NULL;
3809
3810 ret->nb_types = 0;
3811 ret->max_types = 0;
3812 ret->types = NULL;
3813
3814 ret->funcHash = xmlHashCreate(0);
3815
3816 ret->nb_axis = 0;
3817 ret->max_axis = 0;
3818 ret->axis = NULL;
3819
3820 ret->nsHash = NULL;
3821 ret->user = NULL;
3822
3823 ret->contextSize = -1;
3824 ret->proximityPosition = -1;
3825
3826 xmlXPathRegisterAllFunctions(ret);
3827
3828 return(ret);
3829}
3830
3831/**
3832 * xmlXPathFreeContext:
3833 * @ctxt: the context to free
3834 *
3835 * Free up an xmlXPathContext
3836 */
3837void
3838xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3839 xmlXPathRegisteredNsCleanup(ctxt);
3840 xmlXPathRegisteredFuncsCleanup(ctxt);
3841 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003842 xmlFree(ctxt);
3843}
3844
3845/************************************************************************
3846 * *
3847 * Routines to handle XPath parser contexts *
3848 * *
3849 ************************************************************************/
3850
3851#define CHECK_CTXT(ctxt) \
3852 if (ctxt == NULL) { \
3853 xmlGenericError(xmlGenericErrorContext, \
3854 "%s:%d Internal error: ctxt == NULL\n", \
3855 __FILE__, __LINE__); \
3856 } \
3857
3858
3859#define CHECK_CONTEXT(ctxt) \
3860 if (ctxt == NULL) { \
3861 xmlGenericError(xmlGenericErrorContext, \
3862 "%s:%d Internal error: no context\n", \
3863 __FILE__, __LINE__); \
3864 } \
3865 else if (ctxt->doc == NULL) { \
3866 xmlGenericError(xmlGenericErrorContext, \
3867 "%s:%d Internal error: no document\n", \
3868 __FILE__, __LINE__); \
3869 } \
3870 else if (ctxt->doc->children == NULL) { \
3871 xmlGenericError(xmlGenericErrorContext, \
3872 "%s:%d Internal error: document without root\n", \
3873 __FILE__, __LINE__); \
3874 } \
3875
3876
3877/**
3878 * xmlXPathNewParserContext:
3879 * @str: the XPath expression
3880 * @ctxt: the XPath context
3881 *
3882 * Create a new xmlXPathParserContext
3883 *
3884 * Returns the xmlXPathParserContext just allocated.
3885 */
3886xmlXPathParserContextPtr
3887xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3888 xmlXPathParserContextPtr ret;
3889
3890 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3891 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003892 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003893 return(NULL);
3894 }
3895 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3896 ret->cur = ret->base = str;
3897 ret->context = ctxt;
3898
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003899 ret->comp = xmlXPathNewCompExpr();
3900 if (ret->comp == NULL) {
3901 xmlFree(ret->valueTab);
3902 xmlFree(ret);
3903 return(NULL);
3904 }
3905
3906 return(ret);
3907}
3908
3909/**
3910 * xmlXPathCompParserContext:
3911 * @comp: the XPath compiled expression
3912 * @ctxt: the XPath context
3913 *
3914 * Create a new xmlXPathParserContext when processing a compiled expression
3915 *
3916 * Returns the xmlXPathParserContext just allocated.
3917 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003918static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003919xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3920 xmlXPathParserContextPtr ret;
3921
3922 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3923 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003924 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003925 return(NULL);
3926 }
3927 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3928
Owen Taylor3473f882001-02-23 17:55:21 +00003929 /* Allocate the value stack */
3930 ret->valueTab = (xmlXPathObjectPtr *)
3931 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003932 if (ret->valueTab == NULL) {
3933 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003934 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003935 return(NULL);
3936 }
Owen Taylor3473f882001-02-23 17:55:21 +00003937 ret->valueNr = 0;
3938 ret->valueMax = 10;
3939 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003940
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00003941 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003942 ret->comp = comp;
3943
Owen Taylor3473f882001-02-23 17:55:21 +00003944 return(ret);
3945}
3946
3947/**
3948 * xmlXPathFreeParserContext:
3949 * @ctxt: the context to free
3950 *
3951 * Free up an xmlXPathParserContext
3952 */
3953void
3954xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3955 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00003956 xmlFree(ctxt->valueTab);
3957 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003958 if (ctxt->comp)
3959 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00003960 xmlFree(ctxt);
3961}
3962
3963/************************************************************************
3964 * *
3965 * The implicit core function library *
3966 * *
3967 ************************************************************************/
3968
Owen Taylor3473f882001-02-23 17:55:21 +00003969/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003970 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00003971 * @node: a node pointer
3972 *
3973 * Function computing the beginning of the string value of the node,
3974 * used to speed up comparisons
3975 *
3976 * Returns an int usable as a hash
3977 */
3978static unsigned int
3979xmlXPathNodeValHash(xmlNodePtr node) {
3980 int len = 2;
3981 const xmlChar * string = NULL;
3982 xmlNodePtr tmp = NULL;
3983 unsigned int ret = 0;
3984
3985 if (node == NULL)
3986 return(0);
3987
Daniel Veillard9adc0462003-03-24 18:39:54 +00003988 if (node->type == XML_DOCUMENT_NODE) {
3989 tmp = xmlDocGetRootElement((xmlDocPtr) node);
3990 if (tmp == NULL)
3991 node = node->children;
3992 else
3993 node = tmp;
3994
3995 if (node == NULL)
3996 return(0);
3997 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00003998
3999 switch (node->type) {
4000 case XML_COMMENT_NODE:
4001 case XML_PI_NODE:
4002 case XML_CDATA_SECTION_NODE:
4003 case XML_TEXT_NODE:
4004 string = node->content;
4005 if (string == NULL)
4006 return(0);
4007 if (string[0] == 0)
4008 return(0);
4009 return(((unsigned int) string[0]) +
4010 (((unsigned int) string[1]) << 8));
4011 case XML_NAMESPACE_DECL:
4012 string = ((xmlNsPtr)node)->href;
4013 if (string == NULL)
4014 return(0);
4015 if (string[0] == 0)
4016 return(0);
4017 return(((unsigned int) string[0]) +
4018 (((unsigned int) string[1]) << 8));
4019 case XML_ATTRIBUTE_NODE:
4020 tmp = ((xmlAttrPtr) node)->children;
4021 break;
4022 case XML_ELEMENT_NODE:
4023 tmp = node->children;
4024 break;
4025 default:
4026 return(0);
4027 }
4028 while (tmp != NULL) {
4029 switch (tmp->type) {
4030 case XML_COMMENT_NODE:
4031 case XML_PI_NODE:
4032 case XML_CDATA_SECTION_NODE:
4033 case XML_TEXT_NODE:
4034 string = tmp->content;
4035 break;
4036 case XML_NAMESPACE_DECL:
4037 string = ((xmlNsPtr)tmp)->href;
4038 break;
4039 default:
4040 break;
4041 }
4042 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004043 if (len == 1) {
4044 return(ret + (((unsigned int) string[0]) << 8));
4045 }
4046 if (string[1] == 0) {
4047 len = 1;
4048 ret = (unsigned int) string[0];
4049 } else {
4050 return(((unsigned int) string[0]) +
4051 (((unsigned int) string[1]) << 8));
4052 }
4053 }
4054 /*
4055 * Skip to next node
4056 */
4057 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4058 if (tmp->children->type != XML_ENTITY_DECL) {
4059 tmp = tmp->children;
4060 continue;
4061 }
4062 }
4063 if (tmp == node)
4064 break;
4065
4066 if (tmp->next != NULL) {
4067 tmp = tmp->next;
4068 continue;
4069 }
4070
4071 do {
4072 tmp = tmp->parent;
4073 if (tmp == NULL)
4074 break;
4075 if (tmp == node) {
4076 tmp = NULL;
4077 break;
4078 }
4079 if (tmp->next != NULL) {
4080 tmp = tmp->next;
4081 break;
4082 }
4083 } while (tmp != NULL);
4084 }
4085 return(ret);
4086}
4087
4088/**
4089 * xmlXPathStringHash:
4090 * @string: a string
4091 *
4092 * Function computing the beginning of the string value of the node,
4093 * used to speed up comparisons
4094 *
4095 * Returns an int usable as a hash
4096 */
4097static unsigned int
4098xmlXPathStringHash(const xmlChar * string) {
4099 if (string == NULL)
4100 return((unsigned int) 0);
4101 if (string[0] == 0)
4102 return(0);
4103 return(((unsigned int) string[0]) +
4104 (((unsigned int) string[1]) << 8));
4105}
4106
4107/**
Owen Taylor3473f882001-02-23 17:55:21 +00004108 * xmlXPathCompareNodeSetFloat:
4109 * @ctxt: the XPath Parser context
4110 * @inf: less than (1) or greater than (0)
4111 * @strict: is the comparison strict
4112 * @arg: the node set
4113 * @f: the value
4114 *
4115 * Implement the compare operation between a nodeset and a number
4116 * @ns < @val (1, 1, ...
4117 * @ns <= @val (1, 0, ...
4118 * @ns > @val (0, 1, ...
4119 * @ns >= @val (0, 0, ...
4120 *
4121 * If one object to be compared is a node-set and the other is a number,
4122 * then the comparison will be true if and only if there is a node in the
4123 * node-set such that the result of performing the comparison on the number
4124 * to be compared and on the result of converting the string-value of that
4125 * node to a number using the number function is true.
4126 *
4127 * Returns 0 or 1 depending on the results of the test.
4128 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004129static int
Owen Taylor3473f882001-02-23 17:55:21 +00004130xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4131 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4132 int i, ret = 0;
4133 xmlNodeSetPtr ns;
4134 xmlChar *str2;
4135
4136 if ((f == NULL) || (arg == NULL) ||
4137 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4138 xmlXPathFreeObject(arg);
4139 xmlXPathFreeObject(f);
4140 return(0);
4141 }
4142 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004143 if (ns != NULL) {
4144 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004145 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004146 if (str2 != NULL) {
4147 valuePush(ctxt,
4148 xmlXPathNewString(str2));
4149 xmlFree(str2);
4150 xmlXPathNumberFunction(ctxt, 1);
4151 valuePush(ctxt, xmlXPathObjectCopy(f));
4152 ret = xmlXPathCompareValues(ctxt, inf, strict);
4153 if (ret)
4154 break;
4155 }
4156 }
Owen Taylor3473f882001-02-23 17:55:21 +00004157 }
4158 xmlXPathFreeObject(arg);
4159 xmlXPathFreeObject(f);
4160 return(ret);
4161}
4162
4163/**
4164 * xmlXPathCompareNodeSetString:
4165 * @ctxt: the XPath Parser context
4166 * @inf: less than (1) or greater than (0)
4167 * @strict: is the comparison strict
4168 * @arg: the node set
4169 * @s: the value
4170 *
4171 * Implement the compare operation between a nodeset and a string
4172 * @ns < @val (1, 1, ...
4173 * @ns <= @val (1, 0, ...
4174 * @ns > @val (0, 1, ...
4175 * @ns >= @val (0, 0, ...
4176 *
4177 * If one object to be compared is a node-set and the other is a string,
4178 * then the comparison will be true if and only if there is a node in
4179 * the node-set such that the result of performing the comparison on the
4180 * string-value of the node and the other string is true.
4181 *
4182 * Returns 0 or 1 depending on the results of the test.
4183 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004184static int
Owen Taylor3473f882001-02-23 17:55:21 +00004185xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4186 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4187 int i, ret = 0;
4188 xmlNodeSetPtr ns;
4189 xmlChar *str2;
4190
4191 if ((s == NULL) || (arg == NULL) ||
4192 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4193 xmlXPathFreeObject(arg);
4194 xmlXPathFreeObject(s);
4195 return(0);
4196 }
4197 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004198 if (ns != NULL) {
4199 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004200 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004201 if (str2 != NULL) {
4202 valuePush(ctxt,
4203 xmlXPathNewString(str2));
4204 xmlFree(str2);
4205 valuePush(ctxt, xmlXPathObjectCopy(s));
4206 ret = xmlXPathCompareValues(ctxt, inf, strict);
4207 if (ret)
4208 break;
4209 }
4210 }
Owen Taylor3473f882001-02-23 17:55:21 +00004211 }
4212 xmlXPathFreeObject(arg);
4213 xmlXPathFreeObject(s);
4214 return(ret);
4215}
4216
4217/**
4218 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004219 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004220 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004221 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004222 * @arg2: the second node set object
4223 *
4224 * Implement the compare operation on nodesets:
4225 *
4226 * If both objects to be compared are node-sets, then the comparison
4227 * will be true if and only if there is a node in the first node-set
4228 * and a node in the second node-set such that the result of performing
4229 * the comparison on the string-values of the two nodes is true.
4230 * ....
4231 * When neither object to be compared is a node-set and the operator
4232 * is <=, <, >= or >, then the objects are compared by converting both
4233 * objects to numbers and comparing the numbers according to IEEE 754.
4234 * ....
4235 * The number function converts its argument to a number as follows:
4236 * - a string that consists of optional whitespace followed by an
4237 * optional minus sign followed by a Number followed by whitespace
4238 * is converted to the IEEE 754 number that is nearest (according
4239 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4240 * represented by the string; any other string is converted to NaN
4241 *
4242 * Conclusion all nodes need to be converted first to their string value
4243 * and then the comparison must be done when possible
4244 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004245static int
4246xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004247 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4248 int i, j, init = 0;
4249 double val1;
4250 double *values2;
4251 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004252 xmlNodeSetPtr ns1;
4253 xmlNodeSetPtr ns2;
4254
4255 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004256 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4257 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004258 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004259 }
Owen Taylor3473f882001-02-23 17:55:21 +00004260 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004261 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4262 xmlXPathFreeObject(arg1);
4263 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004264 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004265 }
Owen Taylor3473f882001-02-23 17:55:21 +00004266
4267 ns1 = arg1->nodesetval;
4268 ns2 = arg2->nodesetval;
4269
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004270 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004271 xmlXPathFreeObject(arg1);
4272 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004273 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004274 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004275 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004276 xmlXPathFreeObject(arg1);
4277 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004278 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004279 }
Owen Taylor3473f882001-02-23 17:55:21 +00004280
4281 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4282 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004283 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004284 xmlXPathFreeObject(arg1);
4285 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004286 return(0);
4287 }
4288 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004289 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004290 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004291 continue;
4292 for (j = 0;j < ns2->nodeNr;j++) {
4293 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004294 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004295 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004296 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004297 continue;
4298 if (inf && strict)
4299 ret = (val1 < values2[j]);
4300 else if (inf && !strict)
4301 ret = (val1 <= values2[j]);
4302 else if (!inf && strict)
4303 ret = (val1 > values2[j]);
4304 else if (!inf && !strict)
4305 ret = (val1 >= values2[j]);
4306 if (ret)
4307 break;
4308 }
4309 if (ret)
4310 break;
4311 init = 1;
4312 }
4313 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004314 xmlXPathFreeObject(arg1);
4315 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004316 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004317}
4318
4319/**
4320 * xmlXPathCompareNodeSetValue:
4321 * @ctxt: the XPath Parser context
4322 * @inf: less than (1) or greater than (0)
4323 * @strict: is the comparison strict
4324 * @arg: the node set
4325 * @val: the value
4326 *
4327 * Implement the compare operation between a nodeset and a value
4328 * @ns < @val (1, 1, ...
4329 * @ns <= @val (1, 0, ...
4330 * @ns > @val (0, 1, ...
4331 * @ns >= @val (0, 0, ...
4332 *
4333 * If one object to be compared is a node-set and the other is a boolean,
4334 * then the comparison will be true if and only if the result of performing
4335 * the comparison on the boolean and on the result of converting
4336 * the node-set to a boolean using the boolean function is true.
4337 *
4338 * Returns 0 or 1 depending on the results of the test.
4339 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004340static int
Owen Taylor3473f882001-02-23 17:55:21 +00004341xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4342 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4343 if ((val == NULL) || (arg == NULL) ||
4344 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4345 return(0);
4346
4347 switch(val->type) {
4348 case XPATH_NUMBER:
4349 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4350 case XPATH_NODESET:
4351 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004352 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004353 case XPATH_STRING:
4354 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4355 case XPATH_BOOLEAN:
4356 valuePush(ctxt, arg);
4357 xmlXPathBooleanFunction(ctxt, 1);
4358 valuePush(ctxt, val);
4359 return(xmlXPathCompareValues(ctxt, inf, strict));
4360 default:
4361 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004362 }
4363 return(0);
4364}
4365
4366/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004367 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004368 * @arg: the nodeset object argument
4369 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004370 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004371 *
4372 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4373 * If one object to be compared is a node-set and the other is a string,
4374 * then the comparison will be true if and only if there is a node in
4375 * the node-set such that the result of performing the comparison on the
4376 * string-value of the node and the other string is true.
4377 *
4378 * Returns 0 or 1 depending on the results of the test.
4379 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004380static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004381xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004382{
Owen Taylor3473f882001-02-23 17:55:21 +00004383 int i;
4384 xmlNodeSetPtr ns;
4385 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004386 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004387
4388 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004389 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4390 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004391 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004392 /*
4393 * A NULL nodeset compared with a string is always false
4394 * (since there is no node equal, and no node not equal)
4395 */
4396 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004397 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004398 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004399 for (i = 0; i < ns->nodeNr; i++) {
4400 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4401 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4402 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4403 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004404 if (neq)
4405 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004406 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004407 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4408 if (neq)
4409 continue;
4410 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004411 } else if (neq) {
4412 if (str2 != NULL)
4413 xmlFree(str2);
4414 return (1);
4415 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004416 if (str2 != NULL)
4417 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004418 } else if (neq)
4419 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004420 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004421 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004422}
4423
4424/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004425 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004426 * @arg: the nodeset object argument
4427 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004428 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004429 *
4430 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4431 * If one object to be compared is a node-set and the other is a number,
4432 * then the comparison will be true if and only if there is a node in
4433 * the node-set such that the result of performing the comparison on the
4434 * number to be compared and on the result of converting the string-value
4435 * of that node to a number using the number function is true.
4436 *
4437 * Returns 0 or 1 depending on the results of the test.
4438 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004439static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004440xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4441 xmlXPathObjectPtr arg, double f, int neq) {
4442 int i, ret=0;
4443 xmlNodeSetPtr ns;
4444 xmlChar *str2;
4445 xmlXPathObjectPtr val;
4446 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004447
4448 if ((arg == NULL) ||
4449 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4450 return(0);
4451
William M. Brack0c022ad2002-07-12 00:56:01 +00004452 ns = arg->nodesetval;
4453 if (ns != NULL) {
4454 for (i=0;i<ns->nodeNr;i++) {
4455 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4456 if (str2 != NULL) {
4457 valuePush(ctxt, xmlXPathNewString(str2));
4458 xmlFree(str2);
4459 xmlXPathNumberFunction(ctxt, 1);
4460 val = valuePop(ctxt);
4461 v = val->floatval;
4462 xmlXPathFreeObject(val);
4463 if (!xmlXPathIsNaN(v)) {
4464 if ((!neq) && (v==f)) {
4465 ret = 1;
4466 break;
4467 } else if ((neq) && (v!=f)) {
4468 ret = 1;
4469 break;
4470 }
4471 }
4472 }
4473 }
4474 }
4475
4476 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004477}
4478
4479
4480/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004481 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004482 * @arg1: first nodeset object argument
4483 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004484 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004485 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004486 * Implement the equal / not equal operation on XPath nodesets:
4487 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004488 * If both objects to be compared are node-sets, then the comparison
4489 * will be true if and only if there is a node in the first node-set and
4490 * a node in the second node-set such that the result of performing the
4491 * comparison on the string-values of the two nodes is true.
4492 *
4493 * (needless to say, this is a costly operation)
4494 *
4495 * Returns 0 or 1 depending on the results of the test.
4496 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004497static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004498xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004499 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004500 unsigned int *hashs1;
4501 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004502 xmlChar **values1;
4503 xmlChar **values2;
4504 int ret = 0;
4505 xmlNodeSetPtr ns1;
4506 xmlNodeSetPtr ns2;
4507
4508 if ((arg1 == NULL) ||
4509 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4510 return(0);
4511 if ((arg2 == NULL) ||
4512 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4513 return(0);
4514
4515 ns1 = arg1->nodesetval;
4516 ns2 = arg2->nodesetval;
4517
Daniel Veillard911f49a2001-04-07 15:39:35 +00004518 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004519 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004520 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004521 return(0);
4522
4523 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004524 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004525 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004526 if (neq == 0)
4527 for (i = 0;i < ns1->nodeNr;i++)
4528 for (j = 0;j < ns2->nodeNr;j++)
4529 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4530 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004531
4532 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004533 if (values1 == NULL) {
4534 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004535 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004536 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004537 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4538 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004539 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004540 xmlFree(values1);
4541 return(0);
4542 }
Owen Taylor3473f882001-02-23 17:55:21 +00004543 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4544 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4545 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004546 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004547 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004548 xmlFree(values1);
4549 return(0);
4550 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004551 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4552 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004553 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004554 xmlFree(hashs1);
4555 xmlFree(values1);
4556 xmlFree(values2);
4557 return(0);
4558 }
Owen Taylor3473f882001-02-23 17:55:21 +00004559 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4560 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004561 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004562 for (j = 0;j < ns2->nodeNr;j++) {
4563 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004564 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004565 if (hashs1[i] != hashs2[j]) {
4566 if (neq) {
4567 ret = 1;
4568 break;
4569 }
4570 }
4571 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004572 if (values1[i] == NULL)
4573 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4574 if (values2[j] == NULL)
4575 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004576 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004577 if (ret)
4578 break;
4579 }
Owen Taylor3473f882001-02-23 17:55:21 +00004580 }
4581 if (ret)
4582 break;
4583 }
4584 for (i = 0;i < ns1->nodeNr;i++)
4585 if (values1[i] != NULL)
4586 xmlFree(values1[i]);
4587 for (j = 0;j < ns2->nodeNr;j++)
4588 if (values2[j] != NULL)
4589 xmlFree(values2[j]);
4590 xmlFree(values1);
4591 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004592 xmlFree(hashs1);
4593 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004594 return(ret);
4595}
4596
William M. Brack0c022ad2002-07-12 00:56:01 +00004597static int
4598xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4599 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004600 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004601 /*
4602 *At this point we are assured neither arg1 nor arg2
4603 *is a nodeset, so we can just pick the appropriate routine.
4604 */
Owen Taylor3473f882001-02-23 17:55:21 +00004605 switch (arg1->type) {
4606 case XPATH_UNDEFINED:
4607#ifdef DEBUG_EXPR
4608 xmlGenericError(xmlGenericErrorContext,
4609 "Equal: undefined\n");
4610#endif
4611 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004612 case XPATH_BOOLEAN:
4613 switch (arg2->type) {
4614 case XPATH_UNDEFINED:
4615#ifdef DEBUG_EXPR
4616 xmlGenericError(xmlGenericErrorContext,
4617 "Equal: undefined\n");
4618#endif
4619 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004620 case XPATH_BOOLEAN:
4621#ifdef DEBUG_EXPR
4622 xmlGenericError(xmlGenericErrorContext,
4623 "Equal: %d boolean %d \n",
4624 arg1->boolval, arg2->boolval);
4625#endif
4626 ret = (arg1->boolval == arg2->boolval);
4627 break;
4628 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004629 ret = (arg1->boolval ==
4630 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004631 break;
4632 case XPATH_STRING:
4633 if ((arg2->stringval == NULL) ||
4634 (arg2->stringval[0] == 0)) ret = 0;
4635 else
4636 ret = 1;
4637 ret = (arg1->boolval == ret);
4638 break;
4639 case XPATH_USERS:
4640 case XPATH_POINT:
4641 case XPATH_RANGE:
4642 case XPATH_LOCATIONSET:
4643 TODO
4644 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004645 case XPATH_NODESET:
4646 case XPATH_XSLT_TREE:
4647 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004648 }
4649 break;
4650 case XPATH_NUMBER:
4651 switch (arg2->type) {
4652 case XPATH_UNDEFINED:
4653#ifdef DEBUG_EXPR
4654 xmlGenericError(xmlGenericErrorContext,
4655 "Equal: undefined\n");
4656#endif
4657 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004658 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004659 ret = (arg2->boolval==
4660 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004661 break;
4662 case XPATH_STRING:
4663 valuePush(ctxt, arg2);
4664 xmlXPathNumberFunction(ctxt, 1);
4665 arg2 = valuePop(ctxt);
4666 /* no break on purpose */
4667 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004668 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004669 if (xmlXPathIsNaN(arg1->floatval) ||
4670 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004671 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004672 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4673 if (xmlXPathIsInf(arg2->floatval) == 1)
4674 ret = 1;
4675 else
4676 ret = 0;
4677 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4678 if (xmlXPathIsInf(arg2->floatval) == -1)
4679 ret = 1;
4680 else
4681 ret = 0;
4682 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4683 if (xmlXPathIsInf(arg1->floatval) == 1)
4684 ret = 1;
4685 else
4686 ret = 0;
4687 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4688 if (xmlXPathIsInf(arg1->floatval) == -1)
4689 ret = 1;
4690 else
4691 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004692 } else {
4693 ret = (arg1->floatval == arg2->floatval);
4694 }
Owen Taylor3473f882001-02-23 17:55:21 +00004695 break;
4696 case XPATH_USERS:
4697 case XPATH_POINT:
4698 case XPATH_RANGE:
4699 case XPATH_LOCATIONSET:
4700 TODO
4701 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004702 case XPATH_NODESET:
4703 case XPATH_XSLT_TREE:
4704 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004705 }
4706 break;
4707 case XPATH_STRING:
4708 switch (arg2->type) {
4709 case XPATH_UNDEFINED:
4710#ifdef DEBUG_EXPR
4711 xmlGenericError(xmlGenericErrorContext,
4712 "Equal: undefined\n");
4713#endif
4714 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004715 case XPATH_BOOLEAN:
4716 if ((arg1->stringval == NULL) ||
4717 (arg1->stringval[0] == 0)) ret = 0;
4718 else
4719 ret = 1;
4720 ret = (arg2->boolval == ret);
4721 break;
4722 case XPATH_STRING:
4723 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4724 break;
4725 case XPATH_NUMBER:
4726 valuePush(ctxt, arg1);
4727 xmlXPathNumberFunction(ctxt, 1);
4728 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004729 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004730 if (xmlXPathIsNaN(arg1->floatval) ||
4731 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004732 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004733 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4734 if (xmlXPathIsInf(arg2->floatval) == 1)
4735 ret = 1;
4736 else
4737 ret = 0;
4738 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4739 if (xmlXPathIsInf(arg2->floatval) == -1)
4740 ret = 1;
4741 else
4742 ret = 0;
4743 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4744 if (xmlXPathIsInf(arg1->floatval) == 1)
4745 ret = 1;
4746 else
4747 ret = 0;
4748 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4749 if (xmlXPathIsInf(arg1->floatval) == -1)
4750 ret = 1;
4751 else
4752 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004753 } else {
4754 ret = (arg1->floatval == arg2->floatval);
4755 }
Owen Taylor3473f882001-02-23 17:55:21 +00004756 break;
4757 case XPATH_USERS:
4758 case XPATH_POINT:
4759 case XPATH_RANGE:
4760 case XPATH_LOCATIONSET:
4761 TODO
4762 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004763 case XPATH_NODESET:
4764 case XPATH_XSLT_TREE:
4765 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004766 }
4767 break;
4768 case XPATH_USERS:
4769 case XPATH_POINT:
4770 case XPATH_RANGE:
4771 case XPATH_LOCATIONSET:
4772 TODO
4773 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004774 case XPATH_NODESET:
4775 case XPATH_XSLT_TREE:
4776 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004777 }
4778 xmlXPathFreeObject(arg1);
4779 xmlXPathFreeObject(arg2);
4780 return(ret);
4781}
4782
William M. Brack0c022ad2002-07-12 00:56:01 +00004783/**
4784 * xmlXPathEqualValues:
4785 * @ctxt: the XPath Parser context
4786 *
4787 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4788 *
4789 * Returns 0 or 1 depending on the results of the test.
4790 */
4791int
4792xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4793 xmlXPathObjectPtr arg1, arg2, argtmp;
4794 int ret = 0;
4795
4796 arg2 = valuePop(ctxt);
4797 arg1 = valuePop(ctxt);
4798 if ((arg1 == NULL) || (arg2 == NULL)) {
4799 if (arg1 != NULL)
4800 xmlXPathFreeObject(arg1);
4801 else
4802 xmlXPathFreeObject(arg2);
4803 XP_ERROR0(XPATH_INVALID_OPERAND);
4804 }
4805
4806 if (arg1 == arg2) {
4807#ifdef DEBUG_EXPR
4808 xmlGenericError(xmlGenericErrorContext,
4809 "Equal: by pointer\n");
4810#endif
4811 return(1);
4812 }
4813
4814 /*
4815 *If either argument is a nodeset, it's a 'special case'
4816 */
4817 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4818 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4819 /*
4820 *Hack it to assure arg1 is the nodeset
4821 */
4822 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4823 argtmp = arg2;
4824 arg2 = arg1;
4825 arg1 = argtmp;
4826 }
4827 switch (arg2->type) {
4828 case XPATH_UNDEFINED:
4829#ifdef DEBUG_EXPR
4830 xmlGenericError(xmlGenericErrorContext,
4831 "Equal: undefined\n");
4832#endif
4833 break;
4834 case XPATH_NODESET:
4835 case XPATH_XSLT_TREE:
4836 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4837 break;
4838 case XPATH_BOOLEAN:
4839 if ((arg1->nodesetval == NULL) ||
4840 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4841 else
4842 ret = 1;
4843 ret = (ret == arg2->boolval);
4844 break;
4845 case XPATH_NUMBER:
4846 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4847 break;
4848 case XPATH_STRING:
4849 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4850 break;
4851 case XPATH_USERS:
4852 case XPATH_POINT:
4853 case XPATH_RANGE:
4854 case XPATH_LOCATIONSET:
4855 TODO
4856 break;
4857 }
4858 xmlXPathFreeObject(arg1);
4859 xmlXPathFreeObject(arg2);
4860 return(ret);
4861 }
4862
4863 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4864}
4865
4866/**
4867 * xmlXPathNotEqualValues:
4868 * @ctxt: the XPath Parser context
4869 *
4870 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4871 *
4872 * Returns 0 or 1 depending on the results of the test.
4873 */
4874int
4875xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4876 xmlXPathObjectPtr arg1, arg2, argtmp;
4877 int ret = 0;
4878
4879 arg2 = valuePop(ctxt);
4880 arg1 = valuePop(ctxt);
4881 if ((arg1 == NULL) || (arg2 == NULL)) {
4882 if (arg1 != NULL)
4883 xmlXPathFreeObject(arg1);
4884 else
4885 xmlXPathFreeObject(arg2);
4886 XP_ERROR0(XPATH_INVALID_OPERAND);
4887 }
4888
4889 if (arg1 == arg2) {
4890#ifdef DEBUG_EXPR
4891 xmlGenericError(xmlGenericErrorContext,
4892 "NotEqual: by pointer\n");
4893#endif
4894 return(0);
4895 }
4896
4897 /*
4898 *If either argument is a nodeset, it's a 'special case'
4899 */
4900 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4901 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4902 /*
4903 *Hack it to assure arg1 is the nodeset
4904 */
4905 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4906 argtmp = arg2;
4907 arg2 = arg1;
4908 arg1 = argtmp;
4909 }
4910 switch (arg2->type) {
4911 case XPATH_UNDEFINED:
4912#ifdef DEBUG_EXPR
4913 xmlGenericError(xmlGenericErrorContext,
4914 "NotEqual: undefined\n");
4915#endif
4916 break;
4917 case XPATH_NODESET:
4918 case XPATH_XSLT_TREE:
4919 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4920 break;
4921 case XPATH_BOOLEAN:
4922 if ((arg1->nodesetval == NULL) ||
4923 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4924 else
4925 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004926 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004927 break;
4928 case XPATH_NUMBER:
4929 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4930 break;
4931 case XPATH_STRING:
4932 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4933 break;
4934 case XPATH_USERS:
4935 case XPATH_POINT:
4936 case XPATH_RANGE:
4937 case XPATH_LOCATIONSET:
4938 TODO
4939 break;
4940 }
4941 xmlXPathFreeObject(arg1);
4942 xmlXPathFreeObject(arg2);
4943 return(ret);
4944 }
4945
4946 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4947}
Owen Taylor3473f882001-02-23 17:55:21 +00004948
4949/**
4950 * xmlXPathCompareValues:
4951 * @ctxt: the XPath Parser context
4952 * @inf: less than (1) or greater than (0)
4953 * @strict: is the comparison strict
4954 *
4955 * Implement the compare operation on XPath objects:
4956 * @arg1 < @arg2 (1, 1, ...
4957 * @arg1 <= @arg2 (1, 0, ...
4958 * @arg1 > @arg2 (0, 1, ...
4959 * @arg1 >= @arg2 (0, 0, ...
4960 *
4961 * When neither object to be compared is a node-set and the operator is
4962 * <=, <, >=, >, then the objects are compared by converted both objects
4963 * to numbers and comparing the numbers according to IEEE 754. The <
4964 * comparison will be true if and only if the first number is less than the
4965 * second number. The <= comparison will be true if and only if the first
4966 * number is less than or equal to the second number. The > comparison
4967 * will be true if and only if the first number is greater than the second
4968 * number. The >= comparison will be true if and only if the first number
4969 * is greater than or equal to the second number.
4970 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004971 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00004972 */
4973int
4974xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004975 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004976 xmlXPathObjectPtr arg1, arg2;
4977
William M. Brack0c022ad2002-07-12 00:56:01 +00004978 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00004979 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00004980 if ((arg1 == NULL) || (arg2 == NULL)) {
4981 if (arg1 != NULL)
4982 xmlXPathFreeObject(arg1);
4983 else
4984 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004985 XP_ERROR0(XPATH_INVALID_OPERAND);
4986 }
4987
William M. Brack0c022ad2002-07-12 00:56:01 +00004988 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4989 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4990 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4991 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004992 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004993 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00004994 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004995 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4996 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004997 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00004998 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4999 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005000 }
5001 }
5002 return(ret);
5003 }
5004
5005 if (arg1->type != XPATH_NUMBER) {
5006 valuePush(ctxt, arg1);
5007 xmlXPathNumberFunction(ctxt, 1);
5008 arg1 = valuePop(ctxt);
5009 }
5010 if (arg1->type != XPATH_NUMBER) {
5011 xmlXPathFreeObject(arg1);
5012 xmlXPathFreeObject(arg2);
5013 XP_ERROR0(XPATH_INVALID_OPERAND);
5014 }
5015 if (arg2->type != XPATH_NUMBER) {
5016 valuePush(ctxt, arg2);
5017 xmlXPathNumberFunction(ctxt, 1);
5018 arg2 = valuePop(ctxt);
5019 }
5020 if (arg2->type != XPATH_NUMBER) {
5021 xmlXPathFreeObject(arg1);
5022 xmlXPathFreeObject(arg2);
5023 XP_ERROR0(XPATH_INVALID_OPERAND);
5024 }
5025 /*
5026 * Add tests for infinity and nan
5027 * => feedback on 3.4 for Inf and NaN
5028 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005029 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005030 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005031 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005032 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005033 arg1i=xmlXPathIsInf(arg1->floatval);
5034 arg2i=xmlXPathIsInf(arg2->floatval);
5035 if (inf && strict) {
5036 if ((arg1i == -1 && arg2i != -1) ||
5037 (arg2i == 1 && arg1i != 1)) {
5038 ret = 1;
5039 } else if (arg1i == 0 && arg2i == 0) {
5040 ret = (arg1->floatval < arg2->floatval);
5041 } else {
5042 ret = 0;
5043 }
5044 }
5045 else if (inf && !strict) {
5046 if (arg1i == -1 || arg2i == 1) {
5047 ret = 1;
5048 } else if (arg1i == 0 && arg2i == 0) {
5049 ret = (arg1->floatval <= arg2->floatval);
5050 } else {
5051 ret = 0;
5052 }
5053 }
5054 else if (!inf && strict) {
5055 if ((arg1i == 1 && arg2i != 1) ||
5056 (arg2i == -1 && arg1i != -1)) {
5057 ret = 1;
5058 } else if (arg1i == 0 && arg2i == 0) {
5059 ret = (arg1->floatval > arg2->floatval);
5060 } else {
5061 ret = 0;
5062 }
5063 }
5064 else if (!inf && !strict) {
5065 if (arg1i == 1 || arg2i == -1) {
5066 ret = 1;
5067 } else if (arg1i == 0 && arg2i == 0) {
5068 ret = (arg1->floatval >= arg2->floatval);
5069 } else {
5070 ret = 0;
5071 }
5072 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005073 }
Owen Taylor3473f882001-02-23 17:55:21 +00005074 xmlXPathFreeObject(arg1);
5075 xmlXPathFreeObject(arg2);
5076 return(ret);
5077}
5078
5079/**
5080 * xmlXPathValueFlipSign:
5081 * @ctxt: the XPath Parser context
5082 *
5083 * Implement the unary - operation on an XPath object
5084 * The numeric operators convert their operands to numbers as if
5085 * by calling the number function.
5086 */
5087void
5088xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005089 CAST_TO_NUMBER;
5090 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005091 if (xmlXPathIsNaN(ctxt->value->floatval))
5092 ctxt->value->floatval=xmlXPathNAN;
5093 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5094 ctxt->value->floatval=xmlXPathNINF;
5095 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5096 ctxt->value->floatval=xmlXPathPINF;
5097 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005098 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5099 ctxt->value->floatval = xmlXPathNZERO;
5100 else
5101 ctxt->value->floatval = 0;
5102 }
5103 else
5104 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005105}
5106
5107/**
5108 * xmlXPathAddValues:
5109 * @ctxt: the XPath Parser context
5110 *
5111 * Implement the add operation on XPath objects:
5112 * The numeric operators convert their operands to numbers as if
5113 * by calling the number function.
5114 */
5115void
5116xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5117 xmlXPathObjectPtr arg;
5118 double val;
5119
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005120 arg = valuePop(ctxt);
5121 if (arg == NULL)
5122 XP_ERROR(XPATH_INVALID_OPERAND);
5123 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005124 xmlXPathFreeObject(arg);
5125
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005126 CAST_TO_NUMBER;
5127 CHECK_TYPE(XPATH_NUMBER);
5128 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005129}
5130
5131/**
5132 * xmlXPathSubValues:
5133 * @ctxt: the XPath Parser context
5134 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005135 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005136 * The numeric operators convert their operands to numbers as if
5137 * by calling the number function.
5138 */
5139void
5140xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5141 xmlXPathObjectPtr arg;
5142 double val;
5143
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005144 arg = valuePop(ctxt);
5145 if (arg == NULL)
5146 XP_ERROR(XPATH_INVALID_OPERAND);
5147 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005148 xmlXPathFreeObject(arg);
5149
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005150 CAST_TO_NUMBER;
5151 CHECK_TYPE(XPATH_NUMBER);
5152 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005153}
5154
5155/**
5156 * xmlXPathMultValues:
5157 * @ctxt: the XPath Parser context
5158 *
5159 * Implement the multiply operation on XPath objects:
5160 * The numeric operators convert their operands to numbers as if
5161 * by calling the number function.
5162 */
5163void
5164xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5165 xmlXPathObjectPtr arg;
5166 double val;
5167
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005168 arg = valuePop(ctxt);
5169 if (arg == NULL)
5170 XP_ERROR(XPATH_INVALID_OPERAND);
5171 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005172 xmlXPathFreeObject(arg);
5173
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005174 CAST_TO_NUMBER;
5175 CHECK_TYPE(XPATH_NUMBER);
5176 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005177}
5178
5179/**
5180 * xmlXPathDivValues:
5181 * @ctxt: the XPath Parser context
5182 *
5183 * Implement the div operation on XPath objects @arg1 / @arg2:
5184 * The numeric operators convert their operands to numbers as if
5185 * by calling the number function.
5186 */
5187void
5188xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5189 xmlXPathObjectPtr arg;
5190 double val;
5191
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005192 arg = valuePop(ctxt);
5193 if (arg == NULL)
5194 XP_ERROR(XPATH_INVALID_OPERAND);
5195 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005196 xmlXPathFreeObject(arg);
5197
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005198 CAST_TO_NUMBER;
5199 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005200 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5201 ctxt->value->floatval = xmlXPathNAN;
5202 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005203 if (ctxt->value->floatval == 0)
5204 ctxt->value->floatval = xmlXPathNAN;
5205 else if (ctxt->value->floatval > 0)
5206 ctxt->value->floatval = xmlXPathNINF;
5207 else if (ctxt->value->floatval < 0)
5208 ctxt->value->floatval = xmlXPathPINF;
5209 }
5210 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005211 if (ctxt->value->floatval == 0)
5212 ctxt->value->floatval = xmlXPathNAN;
5213 else if (ctxt->value->floatval > 0)
5214 ctxt->value->floatval = xmlXPathPINF;
5215 else if (ctxt->value->floatval < 0)
5216 ctxt->value->floatval = xmlXPathNINF;
5217 } else
5218 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005219}
5220
5221/**
5222 * xmlXPathModValues:
5223 * @ctxt: the XPath Parser context
5224 *
5225 * Implement the mod operation on XPath objects: @arg1 / @arg2
5226 * The numeric operators convert their operands to numbers as if
5227 * by calling the number function.
5228 */
5229void
5230xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5231 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005232 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005233
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005234 arg = valuePop(ctxt);
5235 if (arg == NULL)
5236 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005237 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005238 xmlXPathFreeObject(arg);
5239
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005240 CAST_TO_NUMBER;
5241 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005242 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005243 if (arg2 == 0)
5244 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005245 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005246 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005247 }
Owen Taylor3473f882001-02-23 17:55:21 +00005248}
5249
5250/************************************************************************
5251 * *
5252 * The traversal functions *
5253 * *
5254 ************************************************************************/
5255
Owen Taylor3473f882001-02-23 17:55:21 +00005256/*
5257 * A traversal function enumerates nodes along an axis.
5258 * Initially it must be called with NULL, and it indicates
5259 * termination on the axis by returning NULL.
5260 */
5261typedef xmlNodePtr (*xmlXPathTraversalFunction)
5262 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5263
5264/**
5265 * xmlXPathNextSelf:
5266 * @ctxt: the XPath Parser context
5267 * @cur: the current node in the traversal
5268 *
5269 * Traversal function for the "self" direction
5270 * The self axis contains just the context node itself
5271 *
5272 * Returns the next element following that axis
5273 */
5274xmlNodePtr
5275xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5276 if (cur == NULL)
5277 return(ctxt->context->node);
5278 return(NULL);
5279}
5280
5281/**
5282 * xmlXPathNextChild:
5283 * @ctxt: the XPath Parser context
5284 * @cur: the current node in the traversal
5285 *
5286 * Traversal function for the "child" direction
5287 * The child axis contains the children of the context node in document order.
5288 *
5289 * Returns the next element following that axis
5290 */
5291xmlNodePtr
5292xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5293 if (cur == NULL) {
5294 if (ctxt->context->node == NULL) return(NULL);
5295 switch (ctxt->context->node->type) {
5296 case XML_ELEMENT_NODE:
5297 case XML_TEXT_NODE:
5298 case XML_CDATA_SECTION_NODE:
5299 case XML_ENTITY_REF_NODE:
5300 case XML_ENTITY_NODE:
5301 case XML_PI_NODE:
5302 case XML_COMMENT_NODE:
5303 case XML_NOTATION_NODE:
5304 case XML_DTD_NODE:
5305 return(ctxt->context->node->children);
5306 case XML_DOCUMENT_NODE:
5307 case XML_DOCUMENT_TYPE_NODE:
5308 case XML_DOCUMENT_FRAG_NODE:
5309 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005310#ifdef LIBXML_DOCB_ENABLED
5311 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005312#endif
5313 return(((xmlDocPtr) ctxt->context->node)->children);
5314 case XML_ELEMENT_DECL:
5315 case XML_ATTRIBUTE_DECL:
5316 case XML_ENTITY_DECL:
5317 case XML_ATTRIBUTE_NODE:
5318 case XML_NAMESPACE_DECL:
5319 case XML_XINCLUDE_START:
5320 case XML_XINCLUDE_END:
5321 return(NULL);
5322 }
5323 return(NULL);
5324 }
5325 if ((cur->type == XML_DOCUMENT_NODE) ||
5326 (cur->type == XML_HTML_DOCUMENT_NODE))
5327 return(NULL);
5328 return(cur->next);
5329}
5330
5331/**
5332 * xmlXPathNextDescendant:
5333 * @ctxt: the XPath Parser context
5334 * @cur: the current node in the traversal
5335 *
5336 * Traversal function for the "descendant" direction
5337 * the descendant axis contains the descendants of the context node in document
5338 * order; a descendant is a child or a child of a child and so on.
5339 *
5340 * Returns the next element following that axis
5341 */
5342xmlNodePtr
5343xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5344 if (cur == NULL) {
5345 if (ctxt->context->node == NULL)
5346 return(NULL);
5347 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5348 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5349 return(NULL);
5350
5351 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5352 return(ctxt->context->doc->children);
5353 return(ctxt->context->node->children);
5354 }
5355
Daniel Veillard567e1b42001-08-01 15:53:47 +00005356 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005357 /*
5358 * Do not descend on entities declarations
5359 */
5360 if (cur->children->type != XML_ENTITY_DECL) {
5361 cur = cur->children;
5362 /*
5363 * Skip DTDs
5364 */
5365 if (cur->type != XML_DTD_NODE)
5366 return(cur);
5367 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005368 }
5369
5370 if (cur == ctxt->context->node) return(NULL);
5371
Daniel Veillard68e9e742002-11-16 15:35:11 +00005372 while (cur->next != NULL) {
5373 cur = cur->next;
5374 if ((cur->type != XML_ENTITY_DECL) &&
5375 (cur->type != XML_DTD_NODE))
5376 return(cur);
5377 }
Owen Taylor3473f882001-02-23 17:55:21 +00005378
5379 do {
5380 cur = cur->parent;
5381 if (cur == NULL) return(NULL);
5382 if (cur == ctxt->context->node) return(NULL);
5383 if (cur->next != NULL) {
5384 cur = cur->next;
5385 return(cur);
5386 }
5387 } while (cur != NULL);
5388 return(cur);
5389}
5390
5391/**
5392 * xmlXPathNextDescendantOrSelf:
5393 * @ctxt: the XPath Parser context
5394 * @cur: the current node in the traversal
5395 *
5396 * Traversal function for the "descendant-or-self" direction
5397 * the descendant-or-self axis contains the context node and the descendants
5398 * of the context node in document order; thus the context node is the first
5399 * node on the axis, and the first child of the context node is the second node
5400 * on the axis
5401 *
5402 * Returns the next element following that axis
5403 */
5404xmlNodePtr
5405xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5406 if (cur == NULL) {
5407 if (ctxt->context->node == NULL)
5408 return(NULL);
5409 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5410 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5411 return(NULL);
5412 return(ctxt->context->node);
5413 }
5414
5415 return(xmlXPathNextDescendant(ctxt, cur));
5416}
5417
5418/**
5419 * xmlXPathNextParent:
5420 * @ctxt: the XPath Parser context
5421 * @cur: the current node in the traversal
5422 *
5423 * Traversal function for the "parent" direction
5424 * The parent axis contains the parent of the context node, if there is one.
5425 *
5426 * Returns the next element following that axis
5427 */
5428xmlNodePtr
5429xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5430 /*
5431 * the parent of an attribute or namespace node is the element
5432 * to which the attribute or namespace node is attached
5433 * Namespace handling !!!
5434 */
5435 if (cur == NULL) {
5436 if (ctxt->context->node == NULL) return(NULL);
5437 switch (ctxt->context->node->type) {
5438 case XML_ELEMENT_NODE:
5439 case XML_TEXT_NODE:
5440 case XML_CDATA_SECTION_NODE:
5441 case XML_ENTITY_REF_NODE:
5442 case XML_ENTITY_NODE:
5443 case XML_PI_NODE:
5444 case XML_COMMENT_NODE:
5445 case XML_NOTATION_NODE:
5446 case XML_DTD_NODE:
5447 case XML_ELEMENT_DECL:
5448 case XML_ATTRIBUTE_DECL:
5449 case XML_XINCLUDE_START:
5450 case XML_XINCLUDE_END:
5451 case XML_ENTITY_DECL:
5452 if (ctxt->context->node->parent == NULL)
5453 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005454 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005455 ((ctxt->context->node->parent->name[0] == ' ') ||
5456 (xmlStrEqual(ctxt->context->node->parent->name,
5457 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005458 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005459 return(ctxt->context->node->parent);
5460 case XML_ATTRIBUTE_NODE: {
5461 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5462
5463 return(att->parent);
5464 }
5465 case XML_DOCUMENT_NODE:
5466 case XML_DOCUMENT_TYPE_NODE:
5467 case XML_DOCUMENT_FRAG_NODE:
5468 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005469#ifdef LIBXML_DOCB_ENABLED
5470 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005471#endif
5472 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005473 case XML_NAMESPACE_DECL: {
5474 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5475
5476 if ((ns->next != NULL) &&
5477 (ns->next->type != XML_NAMESPACE_DECL))
5478 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005479 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005480 }
Owen Taylor3473f882001-02-23 17:55:21 +00005481 }
5482 }
5483 return(NULL);
5484}
5485
5486/**
5487 * xmlXPathNextAncestor:
5488 * @ctxt: the XPath Parser context
5489 * @cur: the current node in the traversal
5490 *
5491 * Traversal function for the "ancestor" direction
5492 * the ancestor axis contains the ancestors of the context node; the ancestors
5493 * of the context node consist of the parent of context node and the parent's
5494 * parent and so on; the nodes are ordered in reverse document order; thus the
5495 * parent is the first node on the axis, and the parent's parent is the second
5496 * node on the axis
5497 *
5498 * Returns the next element following that axis
5499 */
5500xmlNodePtr
5501xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5502 /*
5503 * the parent of an attribute or namespace node is the element
5504 * to which the attribute or namespace node is attached
5505 * !!!!!!!!!!!!!
5506 */
5507 if (cur == NULL) {
5508 if (ctxt->context->node == NULL) return(NULL);
5509 switch (ctxt->context->node->type) {
5510 case XML_ELEMENT_NODE:
5511 case XML_TEXT_NODE:
5512 case XML_CDATA_SECTION_NODE:
5513 case XML_ENTITY_REF_NODE:
5514 case XML_ENTITY_NODE:
5515 case XML_PI_NODE:
5516 case XML_COMMENT_NODE:
5517 case XML_DTD_NODE:
5518 case XML_ELEMENT_DECL:
5519 case XML_ATTRIBUTE_DECL:
5520 case XML_ENTITY_DECL:
5521 case XML_NOTATION_NODE:
5522 case XML_XINCLUDE_START:
5523 case XML_XINCLUDE_END:
5524 if (ctxt->context->node->parent == NULL)
5525 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005526 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005527 ((ctxt->context->node->parent->name[0] == ' ') ||
5528 (xmlStrEqual(ctxt->context->node->parent->name,
5529 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005530 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005531 return(ctxt->context->node->parent);
5532 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005533 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005534
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005535 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005536 }
5537 case XML_DOCUMENT_NODE:
5538 case XML_DOCUMENT_TYPE_NODE:
5539 case XML_DOCUMENT_FRAG_NODE:
5540 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005541#ifdef LIBXML_DOCB_ENABLED
5542 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005543#endif
5544 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005545 case XML_NAMESPACE_DECL: {
5546 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5547
5548 if ((ns->next != NULL) &&
5549 (ns->next->type != XML_NAMESPACE_DECL))
5550 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005551 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005552 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005553 }
Owen Taylor3473f882001-02-23 17:55:21 +00005554 }
5555 return(NULL);
5556 }
5557 if (cur == ctxt->context->doc->children)
5558 return((xmlNodePtr) ctxt->context->doc);
5559 if (cur == (xmlNodePtr) ctxt->context->doc)
5560 return(NULL);
5561 switch (cur->type) {
5562 case XML_ELEMENT_NODE:
5563 case XML_TEXT_NODE:
5564 case XML_CDATA_SECTION_NODE:
5565 case XML_ENTITY_REF_NODE:
5566 case XML_ENTITY_NODE:
5567 case XML_PI_NODE:
5568 case XML_COMMENT_NODE:
5569 case XML_NOTATION_NODE:
5570 case XML_DTD_NODE:
5571 case XML_ELEMENT_DECL:
5572 case XML_ATTRIBUTE_DECL:
5573 case XML_ENTITY_DECL:
5574 case XML_XINCLUDE_START:
5575 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005576 if (cur->parent == NULL)
5577 return(NULL);
5578 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005579 ((cur->parent->name[0] == ' ') ||
5580 (xmlStrEqual(cur->parent->name,
5581 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005582 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005583 return(cur->parent);
5584 case XML_ATTRIBUTE_NODE: {
5585 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5586
5587 return(att->parent);
5588 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005589 case XML_NAMESPACE_DECL: {
5590 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5591
5592 if ((ns->next != NULL) &&
5593 (ns->next->type != XML_NAMESPACE_DECL))
5594 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005595 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005596 return(NULL);
5597 }
Owen Taylor3473f882001-02-23 17:55:21 +00005598 case XML_DOCUMENT_NODE:
5599 case XML_DOCUMENT_TYPE_NODE:
5600 case XML_DOCUMENT_FRAG_NODE:
5601 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005602#ifdef LIBXML_DOCB_ENABLED
5603 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005604#endif
5605 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005606 }
5607 return(NULL);
5608}
5609
5610/**
5611 * xmlXPathNextAncestorOrSelf:
5612 * @ctxt: the XPath Parser context
5613 * @cur: the current node in the traversal
5614 *
5615 * Traversal function for the "ancestor-or-self" direction
5616 * he ancestor-or-self axis contains the context node and ancestors of
5617 * the context node in reverse document order; thus the context node is
5618 * the first node on the axis, and the context node's parent the second;
5619 * parent here is defined the same as with the parent axis.
5620 *
5621 * Returns the next element following that axis
5622 */
5623xmlNodePtr
5624xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5625 if (cur == NULL)
5626 return(ctxt->context->node);
5627 return(xmlXPathNextAncestor(ctxt, cur));
5628}
5629
5630/**
5631 * xmlXPathNextFollowingSibling:
5632 * @ctxt: the XPath Parser context
5633 * @cur: the current node in the traversal
5634 *
5635 * Traversal function for the "following-sibling" direction
5636 * The following-sibling axis contains the following siblings of the context
5637 * node in document order.
5638 *
5639 * Returns the next element following that axis
5640 */
5641xmlNodePtr
5642xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5643 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5644 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5645 return(NULL);
5646 if (cur == (xmlNodePtr) ctxt->context->doc)
5647 return(NULL);
5648 if (cur == NULL)
5649 return(ctxt->context->node->next);
5650 return(cur->next);
5651}
5652
5653/**
5654 * xmlXPathNextPrecedingSibling:
5655 * @ctxt: the XPath Parser context
5656 * @cur: the current node in the traversal
5657 *
5658 * Traversal function for the "preceding-sibling" direction
5659 * The preceding-sibling axis contains the preceding siblings of the context
5660 * node in reverse document order; the first preceding sibling is first on the
5661 * axis; the sibling preceding that node is the second on the axis and so on.
5662 *
5663 * Returns the next element following that axis
5664 */
5665xmlNodePtr
5666xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5667 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5668 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5669 return(NULL);
5670 if (cur == (xmlNodePtr) ctxt->context->doc)
5671 return(NULL);
5672 if (cur == NULL)
5673 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005674 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5675 cur = cur->prev;
5676 if (cur == NULL)
5677 return(ctxt->context->node->prev);
5678 }
Owen Taylor3473f882001-02-23 17:55:21 +00005679 return(cur->prev);
5680}
5681
5682/**
5683 * xmlXPathNextFollowing:
5684 * @ctxt: the XPath Parser context
5685 * @cur: the current node in the traversal
5686 *
5687 * Traversal function for the "following" direction
5688 * The following axis contains all nodes in the same document as the context
5689 * node that are after the context node in document order, excluding any
5690 * descendants and excluding attribute nodes and namespace nodes; the nodes
5691 * are ordered in document order
5692 *
5693 * Returns the next element following that axis
5694 */
5695xmlNodePtr
5696xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5697 if (cur != NULL && cur->children != NULL)
5698 return cur->children ;
5699 if (cur == NULL) cur = ctxt->context->node;
5700 if (cur == NULL) return(NULL) ; /* ERROR */
5701 if (cur->next != NULL) return(cur->next) ;
5702 do {
5703 cur = cur->parent;
5704 if (cur == NULL) return(NULL);
5705 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5706 if (cur->next != NULL) return(cur->next);
5707 } while (cur != NULL);
5708 return(cur);
5709}
5710
5711/*
5712 * xmlXPathIsAncestor:
5713 * @ancestor: the ancestor node
5714 * @node: the current node
5715 *
5716 * Check that @ancestor is a @node's ancestor
5717 *
5718 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5719 */
5720static int
5721xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5722 if ((ancestor == NULL) || (node == NULL)) return(0);
5723 /* nodes need to be in the same document */
5724 if (ancestor->doc != node->doc) return(0);
5725 /* avoid searching if ancestor or node is the root node */
5726 if (ancestor == (xmlNodePtr) node->doc) return(1);
5727 if (node == (xmlNodePtr) ancestor->doc) return(0);
5728 while (node->parent != NULL) {
5729 if (node->parent == ancestor)
5730 return(1);
5731 node = node->parent;
5732 }
5733 return(0);
5734}
5735
5736/**
5737 * xmlXPathNextPreceding:
5738 * @ctxt: the XPath Parser context
5739 * @cur: the current node in the traversal
5740 *
5741 * Traversal function for the "preceding" direction
5742 * the preceding axis contains all nodes in the same document as the context
5743 * node that are before the context node in document order, excluding any
5744 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5745 * ordered in reverse document order
5746 *
5747 * Returns the next element following that axis
5748 */
5749xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005750xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5751{
Owen Taylor3473f882001-02-23 17:55:21 +00005752 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005753 cur = ctxt->context->node;
5754 if (cur == NULL)
5755 return (NULL);
5756 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5757 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005758 do {
5759 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005760 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5761 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005762 }
5763
5764 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005765 if (cur == NULL)
5766 return (NULL);
5767 if (cur == ctxt->context->doc->children)
5768 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005769 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005770 return (cur);
5771}
5772
5773/**
5774 * xmlXPathNextPrecedingInternal:
5775 * @ctxt: the XPath Parser context
5776 * @cur: the current node in the traversal
5777 *
5778 * Traversal function for the "preceding" direction
5779 * the preceding axis contains all nodes in the same document as the context
5780 * node that are before the context node in document order, excluding any
5781 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5782 * ordered in reverse document order
5783 * This is a faster implementation but internal only since it requires a
5784 * state kept in the parser context: ctxt->ancestor.
5785 *
5786 * Returns the next element following that axis
5787 */
5788static xmlNodePtr
5789xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5790 xmlNodePtr cur)
5791{
5792 if (cur == NULL) {
5793 cur = ctxt->context->node;
5794 if (cur == NULL)
5795 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005796 if (cur->type == XML_NAMESPACE_DECL)
5797 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005798 ctxt->ancestor = cur->parent;
5799 }
5800 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5801 cur = cur->prev;
5802 while (cur->prev == NULL) {
5803 cur = cur->parent;
5804 if (cur == NULL)
5805 return (NULL);
5806 if (cur == ctxt->context->doc->children)
5807 return (NULL);
5808 if (cur != ctxt->ancestor)
5809 return (cur);
5810 ctxt->ancestor = cur->parent;
5811 }
5812 cur = cur->prev;
5813 while (cur->last != NULL)
5814 cur = cur->last;
5815 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005816}
5817
5818/**
5819 * xmlXPathNextNamespace:
5820 * @ctxt: the XPath Parser context
5821 * @cur: the current attribute in the traversal
5822 *
5823 * Traversal function for the "namespace" direction
5824 * the namespace axis contains the namespace nodes of the context node;
5825 * the order of nodes on this axis is implementation-defined; the axis will
5826 * be empty unless the context node is an element
5827 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005828 * We keep the XML namespace node at the end of the list.
5829 *
Owen Taylor3473f882001-02-23 17:55:21 +00005830 * Returns the next element following that axis
5831 */
5832xmlNodePtr
5833xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5834 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005835 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005836 if (ctxt->context->tmpNsList != NULL)
5837 xmlFree(ctxt->context->tmpNsList);
5838 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005839 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005840 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005841 if (ctxt->context->tmpNsList != NULL) {
5842 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5843 ctxt->context->tmpNsNr++;
5844 }
5845 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005846 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005847 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005848 if (ctxt->context->tmpNsNr > 0) {
5849 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5850 } else {
5851 if (ctxt->context->tmpNsList != NULL)
5852 xmlFree(ctxt->context->tmpNsList);
5853 ctxt->context->tmpNsList = NULL;
5854 return(NULL);
5855 }
Owen Taylor3473f882001-02-23 17:55:21 +00005856}
5857
5858/**
5859 * xmlXPathNextAttribute:
5860 * @ctxt: the XPath Parser context
5861 * @cur: the current attribute in the traversal
5862 *
5863 * Traversal function for the "attribute" direction
5864 * TODO: support DTD inherited default attributes
5865 *
5866 * Returns the next element following that axis
5867 */
5868xmlNodePtr
5869xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005870 if (ctxt->context->node == NULL)
5871 return(NULL);
5872 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5873 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005874 if (cur == NULL) {
5875 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5876 return(NULL);
5877 return((xmlNodePtr)ctxt->context->node->properties);
5878 }
5879 return((xmlNodePtr)cur->next);
5880}
5881
5882/************************************************************************
5883 * *
5884 * NodeTest Functions *
5885 * *
5886 ************************************************************************/
5887
Owen Taylor3473f882001-02-23 17:55:21 +00005888#define IS_FUNCTION 200
5889
Owen Taylor3473f882001-02-23 17:55:21 +00005890
5891/************************************************************************
5892 * *
5893 * Implicit tree core function library *
5894 * *
5895 ************************************************************************/
5896
5897/**
5898 * xmlXPathRoot:
5899 * @ctxt: the XPath Parser context
5900 *
5901 * Initialize the context to the root of the document
5902 */
5903void
5904xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5905 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5906 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5907}
5908
5909/************************************************************************
5910 * *
5911 * The explicit core function library *
5912 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5913 * *
5914 ************************************************************************/
5915
5916
5917/**
5918 * xmlXPathLastFunction:
5919 * @ctxt: the XPath Parser context
5920 * @nargs: the number of arguments
5921 *
5922 * Implement the last() XPath function
5923 * number last()
5924 * The last function returns the number of nodes in the context node list.
5925 */
5926void
5927xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5928 CHECK_ARITY(0);
5929 if (ctxt->context->contextSize >= 0) {
5930 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5931#ifdef DEBUG_EXPR
5932 xmlGenericError(xmlGenericErrorContext,
5933 "last() : %d\n", ctxt->context->contextSize);
5934#endif
5935 } else {
5936 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5937 }
5938}
5939
5940/**
5941 * xmlXPathPositionFunction:
5942 * @ctxt: the XPath Parser context
5943 * @nargs: the number of arguments
5944 *
5945 * Implement the position() XPath function
5946 * number position()
5947 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005948 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00005949 * will be equal to last().
5950 */
5951void
5952xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5953 CHECK_ARITY(0);
5954 if (ctxt->context->proximityPosition >= 0) {
5955 valuePush(ctxt,
5956 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5957#ifdef DEBUG_EXPR
5958 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5959 ctxt->context->proximityPosition);
5960#endif
5961 } else {
5962 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5963 }
5964}
5965
5966/**
5967 * xmlXPathCountFunction:
5968 * @ctxt: the XPath Parser context
5969 * @nargs: the number of arguments
5970 *
5971 * Implement the count() XPath function
5972 * number count(node-set)
5973 */
5974void
5975xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5976 xmlXPathObjectPtr cur;
5977
5978 CHECK_ARITY(1);
5979 if ((ctxt->value == NULL) ||
5980 ((ctxt->value->type != XPATH_NODESET) &&
5981 (ctxt->value->type != XPATH_XSLT_TREE)))
5982 XP_ERROR(XPATH_INVALID_TYPE);
5983 cur = valuePop(ctxt);
5984
Daniel Veillard911f49a2001-04-07 15:39:35 +00005985 if ((cur == NULL) || (cur->nodesetval == NULL))
5986 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00005987 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00005988 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00005989 } else {
5990 if ((cur->nodesetval->nodeNr != 1) ||
5991 (cur->nodesetval->nodeTab == NULL)) {
5992 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5993 } else {
5994 xmlNodePtr tmp;
5995 int i = 0;
5996
5997 tmp = cur->nodesetval->nodeTab[0];
5998 if (tmp != NULL) {
5999 tmp = tmp->children;
6000 while (tmp != NULL) {
6001 tmp = tmp->next;
6002 i++;
6003 }
6004 }
6005 valuePush(ctxt, xmlXPathNewFloat((double) i));
6006 }
6007 }
Owen Taylor3473f882001-02-23 17:55:21 +00006008 xmlXPathFreeObject(cur);
6009}
6010
6011/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006012 * xmlXPathGetElementsByIds:
6013 * @doc: the document
6014 * @ids: a whitespace separated list of IDs
6015 *
6016 * Selects elements by their unique ID.
6017 *
6018 * Returns a node-set of selected elements.
6019 */
6020static xmlNodeSetPtr
6021xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6022 xmlNodeSetPtr ret;
6023 const xmlChar *cur = ids;
6024 xmlChar *ID;
6025 xmlAttrPtr attr;
6026 xmlNodePtr elem = NULL;
6027
Daniel Veillard7a985a12003-07-06 17:57:42 +00006028 if (ids == NULL) return(NULL);
6029
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006030 ret = xmlXPathNodeSetCreate(NULL);
6031
William M. Brack76e95df2003-10-18 16:20:14 +00006032 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006033 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006034 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006035 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006036
6037 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006038 if (ID != NULL) {
6039 if (xmlValidateNCName(ID, 1) == 0) {
6040 attr = xmlGetID(doc, ID);
6041 if (attr != NULL) {
6042 if (attr->type == XML_ATTRIBUTE_NODE)
6043 elem = attr->parent;
6044 else if (attr->type == XML_ELEMENT_NODE)
6045 elem = (xmlNodePtr) attr;
6046 else
6047 elem = NULL;
6048 if (elem != NULL)
6049 xmlXPathNodeSetAdd(ret, elem);
6050 }
6051 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006052 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006053 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006054
William M. Brack76e95df2003-10-18 16:20:14 +00006055 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006056 ids = cur;
6057 }
6058 return(ret);
6059}
6060
6061/**
Owen Taylor3473f882001-02-23 17:55:21 +00006062 * xmlXPathIdFunction:
6063 * @ctxt: the XPath Parser context
6064 * @nargs: the number of arguments
6065 *
6066 * Implement the id() XPath function
6067 * node-set id(object)
6068 * The id function selects elements by their unique ID
6069 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6070 * then the result is the union of the result of applying id to the
6071 * string value of each of the nodes in the argument node-set. When the
6072 * argument to id is of any other type, the argument is converted to a
6073 * string as if by a call to the string function; the string is split
6074 * into a whitespace-separated list of tokens (whitespace is any sequence
6075 * of characters matching the production S); the result is a node-set
6076 * containing the elements in the same document as the context node that
6077 * have a unique ID equal to any of the tokens in the list.
6078 */
6079void
6080xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006081 xmlChar *tokens;
6082 xmlNodeSetPtr ret;
6083 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006084
6085 CHECK_ARITY(1);
6086 obj = valuePop(ctxt);
6087 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006088 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006089 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006090 int i;
6091
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006092 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006093
Daniel Veillard911f49a2001-04-07 15:39:35 +00006094 if (obj->nodesetval != NULL) {
6095 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006096 tokens =
6097 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6098 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6099 ret = xmlXPathNodeSetMerge(ret, ns);
6100 xmlXPathFreeNodeSet(ns);
6101 if (tokens != NULL)
6102 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006103 }
Owen Taylor3473f882001-02-23 17:55:21 +00006104 }
6105
6106 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006107 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006108 return;
6109 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006110 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006111
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006112 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6113 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006114
Owen Taylor3473f882001-02-23 17:55:21 +00006115 xmlXPathFreeObject(obj);
6116 return;
6117}
6118
6119/**
6120 * xmlXPathLocalNameFunction:
6121 * @ctxt: the XPath Parser context
6122 * @nargs: the number of arguments
6123 *
6124 * Implement the local-name() XPath function
6125 * string local-name(node-set?)
6126 * The local-name function returns a string containing the local part
6127 * of the name of the node in the argument node-set that is first in
6128 * document order. If the node-set is empty or the first node has no
6129 * name, an empty string is returned. If the argument is omitted it
6130 * defaults to the context node.
6131 */
6132void
6133xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6134 xmlXPathObjectPtr cur;
6135
6136 if (nargs == 0) {
6137 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6138 nargs = 1;
6139 }
6140
6141 CHECK_ARITY(1);
6142 if ((ctxt->value == NULL) ||
6143 ((ctxt->value->type != XPATH_NODESET) &&
6144 (ctxt->value->type != XPATH_XSLT_TREE)))
6145 XP_ERROR(XPATH_INVALID_TYPE);
6146 cur = valuePop(ctxt);
6147
Daniel Veillard911f49a2001-04-07 15:39:35 +00006148 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006149 valuePush(ctxt, xmlXPathNewCString(""));
6150 } else {
6151 int i = 0; /* Should be first in document order !!!!! */
6152 switch (cur->nodesetval->nodeTab[i]->type) {
6153 case XML_ELEMENT_NODE:
6154 case XML_ATTRIBUTE_NODE:
6155 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006156 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6157 valuePush(ctxt, xmlXPathNewCString(""));
6158 else
6159 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006160 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6161 break;
6162 case XML_NAMESPACE_DECL:
6163 valuePush(ctxt, xmlXPathNewString(
6164 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6165 break;
6166 default:
6167 valuePush(ctxt, xmlXPathNewCString(""));
6168 }
6169 }
6170 xmlXPathFreeObject(cur);
6171}
6172
6173/**
6174 * xmlXPathNamespaceURIFunction:
6175 * @ctxt: the XPath Parser context
6176 * @nargs: the number of arguments
6177 *
6178 * Implement the namespace-uri() XPath function
6179 * string namespace-uri(node-set?)
6180 * The namespace-uri function returns a string containing the
6181 * namespace URI of the expanded name of the node in the argument
6182 * node-set that is first in document order. If the node-set is empty,
6183 * the first node has no name, or the expanded name has no namespace
6184 * URI, an empty string is returned. If the argument is omitted it
6185 * defaults to the context node.
6186 */
6187void
6188xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6189 xmlXPathObjectPtr cur;
6190
6191 if (nargs == 0) {
6192 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6193 nargs = 1;
6194 }
6195 CHECK_ARITY(1);
6196 if ((ctxt->value == NULL) ||
6197 ((ctxt->value->type != XPATH_NODESET) &&
6198 (ctxt->value->type != XPATH_XSLT_TREE)))
6199 XP_ERROR(XPATH_INVALID_TYPE);
6200 cur = valuePop(ctxt);
6201
Daniel Veillard911f49a2001-04-07 15:39:35 +00006202 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006203 valuePush(ctxt, xmlXPathNewCString(""));
6204 } else {
6205 int i = 0; /* Should be first in document order !!!!! */
6206 switch (cur->nodesetval->nodeTab[i]->type) {
6207 case XML_ELEMENT_NODE:
6208 case XML_ATTRIBUTE_NODE:
6209 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6210 valuePush(ctxt, xmlXPathNewCString(""));
6211 else
6212 valuePush(ctxt, xmlXPathNewString(
6213 cur->nodesetval->nodeTab[i]->ns->href));
6214 break;
6215 default:
6216 valuePush(ctxt, xmlXPathNewCString(""));
6217 }
6218 }
6219 xmlXPathFreeObject(cur);
6220}
6221
6222/**
6223 * xmlXPathNameFunction:
6224 * @ctxt: the XPath Parser context
6225 * @nargs: the number of arguments
6226 *
6227 * Implement the name() XPath function
6228 * string name(node-set?)
6229 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006230 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006231 * order. The QName must represent the name with respect to the namespace
6232 * declarations in effect on the node whose name is being represented.
6233 * Typically, this will be the form in which the name occurred in the XML
6234 * source. This need not be the case if there are namespace declarations
6235 * in effect on the node that associate multiple prefixes with the same
6236 * namespace. However, an implementation may include information about
6237 * the original prefix in its representation of nodes; in this case, an
6238 * implementation can ensure that the returned string is always the same
6239 * as the QName used in the XML source. If the argument it omitted it
6240 * defaults to the context node.
6241 * Libxml keep the original prefix so the "real qualified name" used is
6242 * returned.
6243 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006244static void
Daniel Veillard04383752001-07-08 14:27:15 +00006245xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6246{
Owen Taylor3473f882001-02-23 17:55:21 +00006247 xmlXPathObjectPtr cur;
6248
6249 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006250 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6251 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006252 }
6253
6254 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006255 if ((ctxt->value == NULL) ||
6256 ((ctxt->value->type != XPATH_NODESET) &&
6257 (ctxt->value->type != XPATH_XSLT_TREE)))
6258 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006259 cur = valuePop(ctxt);
6260
Daniel Veillard911f49a2001-04-07 15:39:35 +00006261 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006262 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006263 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006264 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006265
Daniel Veillard04383752001-07-08 14:27:15 +00006266 switch (cur->nodesetval->nodeTab[i]->type) {
6267 case XML_ELEMENT_NODE:
6268 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006269 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6270 valuePush(ctxt, xmlXPathNewCString(""));
6271 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6272 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006273 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006274 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006275
Daniel Veillard652d8a92003-02-04 19:28:49 +00006276 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006277 xmlChar *fullname;
6278
6279 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6280 cur->nodesetval->nodeTab[i]->ns->prefix,
6281 NULL, 0);
6282 if (fullname == cur->nodesetval->nodeTab[i]->name)
6283 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6284 if (fullname == NULL) {
6285 XP_ERROR(XPATH_MEMORY_ERROR);
6286 }
6287 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006288 }
6289 break;
6290 default:
6291 valuePush(ctxt,
6292 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6293 xmlXPathLocalNameFunction(ctxt, 1);
6294 }
Owen Taylor3473f882001-02-23 17:55:21 +00006295 }
6296 xmlXPathFreeObject(cur);
6297}
6298
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006299
6300/**
Owen Taylor3473f882001-02-23 17:55:21 +00006301 * xmlXPathStringFunction:
6302 * @ctxt: the XPath Parser context
6303 * @nargs: the number of arguments
6304 *
6305 * Implement the string() XPath function
6306 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006307 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006308 * - A node-set is converted to a string by returning the value of
6309 * the node in the node-set that is first in document order.
6310 * If the node-set is empty, an empty string is returned.
6311 * - A number is converted to a string as follows
6312 * + NaN is converted to the string NaN
6313 * + positive zero is converted to the string 0
6314 * + negative zero is converted to the string 0
6315 * + positive infinity is converted to the string Infinity
6316 * + negative infinity is converted to the string -Infinity
6317 * + if the number is an integer, the number is represented in
6318 * decimal form as a Number with no decimal point and no leading
6319 * zeros, preceded by a minus sign (-) if the number is negative
6320 * + otherwise, the number is represented in decimal form as a
6321 * Number including a decimal point with at least one digit
6322 * before the decimal point and at least one digit after the
6323 * decimal point, preceded by a minus sign (-) if the number
6324 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006325 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006326 * before the decimal point; beyond the one required digit
6327 * after the decimal point there must be as many, but only as
6328 * many, more digits as are needed to uniquely distinguish the
6329 * number from all other IEEE 754 numeric values.
6330 * - The boolean false value is converted to the string false.
6331 * The boolean true value is converted to the string true.
6332 *
6333 * If the argument is omitted, it defaults to a node-set with the
6334 * context node as its only member.
6335 */
6336void
6337xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6338 xmlXPathObjectPtr cur;
6339
6340 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006341 valuePush(ctxt,
6342 xmlXPathWrapString(
6343 xmlXPathCastNodeToString(ctxt->context->node)));
6344 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006345 }
6346
6347 CHECK_ARITY(1);
6348 cur = valuePop(ctxt);
6349 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006350 cur = xmlXPathConvertString(cur);
6351 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006352}
6353
6354/**
6355 * xmlXPathStringLengthFunction:
6356 * @ctxt: the XPath Parser context
6357 * @nargs: the number of arguments
6358 *
6359 * Implement the string-length() XPath function
6360 * number string-length(string?)
6361 * The string-length returns the number of characters in the string
6362 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6363 * the context node converted to a string, in other words the value
6364 * of the context node.
6365 */
6366void
6367xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6368 xmlXPathObjectPtr cur;
6369
6370 if (nargs == 0) {
6371 if (ctxt->context->node == NULL) {
6372 valuePush(ctxt, xmlXPathNewFloat(0));
6373 } else {
6374 xmlChar *content;
6375
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006376 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006377 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006378 xmlFree(content);
6379 }
6380 return;
6381 }
6382 CHECK_ARITY(1);
6383 CAST_TO_STRING;
6384 CHECK_TYPE(XPATH_STRING);
6385 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006386 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006387 xmlXPathFreeObject(cur);
6388}
6389
6390/**
6391 * xmlXPathConcatFunction:
6392 * @ctxt: the XPath Parser context
6393 * @nargs: the number of arguments
6394 *
6395 * Implement the concat() XPath function
6396 * string concat(string, string, string*)
6397 * The concat function returns the concatenation of its arguments.
6398 */
6399void
6400xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6401 xmlXPathObjectPtr cur, newobj;
6402 xmlChar *tmp;
6403
6404 if (nargs < 2) {
6405 CHECK_ARITY(2);
6406 }
6407
6408 CAST_TO_STRING;
6409 cur = valuePop(ctxt);
6410 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6411 xmlXPathFreeObject(cur);
6412 return;
6413 }
6414 nargs--;
6415
6416 while (nargs > 0) {
6417 CAST_TO_STRING;
6418 newobj = valuePop(ctxt);
6419 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6420 xmlXPathFreeObject(newobj);
6421 xmlXPathFreeObject(cur);
6422 XP_ERROR(XPATH_INVALID_TYPE);
6423 }
6424 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6425 newobj->stringval = cur->stringval;
6426 cur->stringval = tmp;
6427
6428 xmlXPathFreeObject(newobj);
6429 nargs--;
6430 }
6431 valuePush(ctxt, cur);
6432}
6433
6434/**
6435 * xmlXPathContainsFunction:
6436 * @ctxt: the XPath Parser context
6437 * @nargs: the number of arguments
6438 *
6439 * Implement the contains() XPath function
6440 * boolean contains(string, string)
6441 * The contains function returns true if the first argument string
6442 * contains the second argument string, and otherwise returns false.
6443 */
6444void
6445xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6446 xmlXPathObjectPtr hay, needle;
6447
6448 CHECK_ARITY(2);
6449 CAST_TO_STRING;
6450 CHECK_TYPE(XPATH_STRING);
6451 needle = valuePop(ctxt);
6452 CAST_TO_STRING;
6453 hay = valuePop(ctxt);
6454 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6455 xmlXPathFreeObject(hay);
6456 xmlXPathFreeObject(needle);
6457 XP_ERROR(XPATH_INVALID_TYPE);
6458 }
6459 if (xmlStrstr(hay->stringval, needle->stringval))
6460 valuePush(ctxt, xmlXPathNewBoolean(1));
6461 else
6462 valuePush(ctxt, xmlXPathNewBoolean(0));
6463 xmlXPathFreeObject(hay);
6464 xmlXPathFreeObject(needle);
6465}
6466
6467/**
6468 * xmlXPathStartsWithFunction:
6469 * @ctxt: the XPath Parser context
6470 * @nargs: the number of arguments
6471 *
6472 * Implement the starts-with() XPath function
6473 * boolean starts-with(string, string)
6474 * The starts-with function returns true if the first argument string
6475 * starts with the second argument string, and otherwise returns false.
6476 */
6477void
6478xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6479 xmlXPathObjectPtr hay, needle;
6480 int n;
6481
6482 CHECK_ARITY(2);
6483 CAST_TO_STRING;
6484 CHECK_TYPE(XPATH_STRING);
6485 needle = valuePop(ctxt);
6486 CAST_TO_STRING;
6487 hay = valuePop(ctxt);
6488 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6489 xmlXPathFreeObject(hay);
6490 xmlXPathFreeObject(needle);
6491 XP_ERROR(XPATH_INVALID_TYPE);
6492 }
6493 n = xmlStrlen(needle->stringval);
6494 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6495 valuePush(ctxt, xmlXPathNewBoolean(0));
6496 else
6497 valuePush(ctxt, xmlXPathNewBoolean(1));
6498 xmlXPathFreeObject(hay);
6499 xmlXPathFreeObject(needle);
6500}
6501
6502/**
6503 * xmlXPathSubstringFunction:
6504 * @ctxt: the XPath Parser context
6505 * @nargs: the number of arguments
6506 *
6507 * Implement the substring() XPath function
6508 * string substring(string, number, number?)
6509 * The substring function returns the substring of the first argument
6510 * starting at the position specified in the second argument with
6511 * length specified in the third argument. For example,
6512 * substring("12345",2,3) returns "234". If the third argument is not
6513 * specified, it returns the substring starting at the position specified
6514 * in the second argument and continuing to the end of the string. For
6515 * example, substring("12345",2) returns "2345". More precisely, each
6516 * character in the string (see [3.6 Strings]) is considered to have a
6517 * numeric position: the position of the first character is 1, the position
6518 * of the second character is 2 and so on. The returned substring contains
6519 * those characters for which the position of the character is greater than
6520 * or equal to the second argument and, if the third argument is specified,
6521 * less than the sum of the second and third arguments; the comparisons
6522 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6523 * - substring("12345", 1.5, 2.6) returns "234"
6524 * - substring("12345", 0, 3) returns "12"
6525 * - substring("12345", 0 div 0, 3) returns ""
6526 * - substring("12345", 1, 0 div 0) returns ""
6527 * - substring("12345", -42, 1 div 0) returns "12345"
6528 * - substring("12345", -1 div 0, 1 div 0) returns ""
6529 */
6530void
6531xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6532 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006533 double le=0, in;
6534 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006535 xmlChar *ret;
6536
Owen Taylor3473f882001-02-23 17:55:21 +00006537 if (nargs < 2) {
6538 CHECK_ARITY(2);
6539 }
6540 if (nargs > 3) {
6541 CHECK_ARITY(3);
6542 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006543 /*
6544 * take care of possible last (position) argument
6545 */
Owen Taylor3473f882001-02-23 17:55:21 +00006546 if (nargs == 3) {
6547 CAST_TO_NUMBER;
6548 CHECK_TYPE(XPATH_NUMBER);
6549 len = valuePop(ctxt);
6550 le = len->floatval;
6551 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006552 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006553
Owen Taylor3473f882001-02-23 17:55:21 +00006554 CAST_TO_NUMBER;
6555 CHECK_TYPE(XPATH_NUMBER);
6556 start = valuePop(ctxt);
6557 in = start->floatval;
6558 xmlXPathFreeObject(start);
6559 CAST_TO_STRING;
6560 CHECK_TYPE(XPATH_STRING);
6561 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006562 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006563
Daniel Veillard97ac1312001-05-30 19:14:17 +00006564 /*
6565 * If last pos not present, calculate last position
6566 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006567 if (nargs != 3) {
6568 le = (double)m;
6569 if (in < 1.0)
6570 in = 1.0;
6571 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006572
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006573 /* Need to check for the special cases where either
6574 * the index is NaN, the length is NaN, or both
6575 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006576 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006577 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006578 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006579 * To meet the requirements of the spec, the arguments
6580 * must be converted to integer format before
6581 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006582 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006583 * First we go to integer form, rounding up
6584 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006585 */
6586 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006587 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006588
Daniel Veillard9e412302002-06-10 15:59:44 +00006589 if (xmlXPathIsInf(le) == 1) {
6590 l = m;
6591 if (i < 1)
6592 i = 1;
6593 }
6594 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6595 l = 0;
6596 else {
6597 l = (int) le;
6598 if (((double)l)+0.5 <= le) l++;
6599 }
6600
6601 /* Now we normalize inidices */
6602 i -= 1;
6603 l += i;
6604 if (i < 0)
6605 i = 0;
6606 if (l > m)
6607 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006608
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006609 /* number of chars to copy */
6610 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006611
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006612 ret = xmlUTF8Strsub(str->stringval, i, l);
6613 }
6614 else {
6615 ret = NULL;
6616 }
6617
Owen Taylor3473f882001-02-23 17:55:21 +00006618 if (ret == NULL)
6619 valuePush(ctxt, xmlXPathNewCString(""));
6620 else {
6621 valuePush(ctxt, xmlXPathNewString(ret));
6622 xmlFree(ret);
6623 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006624
Owen Taylor3473f882001-02-23 17:55:21 +00006625 xmlXPathFreeObject(str);
6626}
6627
6628/**
6629 * xmlXPathSubstringBeforeFunction:
6630 * @ctxt: the XPath Parser context
6631 * @nargs: the number of arguments
6632 *
6633 * Implement the substring-before() XPath function
6634 * string substring-before(string, string)
6635 * The substring-before function returns the substring of the first
6636 * argument string that precedes the first occurrence of the second
6637 * argument string in the first argument string, or the empty string
6638 * if the first argument string does not contain the second argument
6639 * string. For example, substring-before("1999/04/01","/") returns 1999.
6640 */
6641void
6642xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6643 xmlXPathObjectPtr str;
6644 xmlXPathObjectPtr find;
6645 xmlBufferPtr target;
6646 const xmlChar *point;
6647 int offset;
6648
6649 CHECK_ARITY(2);
6650 CAST_TO_STRING;
6651 find = valuePop(ctxt);
6652 CAST_TO_STRING;
6653 str = valuePop(ctxt);
6654
6655 target = xmlBufferCreate();
6656 if (target) {
6657 point = xmlStrstr(str->stringval, find->stringval);
6658 if (point) {
6659 offset = (int)(point - str->stringval);
6660 xmlBufferAdd(target, str->stringval, offset);
6661 }
6662 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6663 xmlBufferFree(target);
6664 }
6665
6666 xmlXPathFreeObject(str);
6667 xmlXPathFreeObject(find);
6668}
6669
6670/**
6671 * xmlXPathSubstringAfterFunction:
6672 * @ctxt: the XPath Parser context
6673 * @nargs: the number of arguments
6674 *
6675 * Implement the substring-after() XPath function
6676 * string substring-after(string, string)
6677 * The substring-after function returns the substring of the first
6678 * argument string that follows the first occurrence of the second
6679 * argument string in the first argument string, or the empty stringi
6680 * if the first argument string does not contain the second argument
6681 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6682 * and substring-after("1999/04/01","19") returns 99/04/01.
6683 */
6684void
6685xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6686 xmlXPathObjectPtr str;
6687 xmlXPathObjectPtr find;
6688 xmlBufferPtr target;
6689 const xmlChar *point;
6690 int offset;
6691
6692 CHECK_ARITY(2);
6693 CAST_TO_STRING;
6694 find = valuePop(ctxt);
6695 CAST_TO_STRING;
6696 str = valuePop(ctxt);
6697
6698 target = xmlBufferCreate();
6699 if (target) {
6700 point = xmlStrstr(str->stringval, find->stringval);
6701 if (point) {
6702 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6703 xmlBufferAdd(target, &str->stringval[offset],
6704 xmlStrlen(str->stringval) - offset);
6705 }
6706 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6707 xmlBufferFree(target);
6708 }
6709
6710 xmlXPathFreeObject(str);
6711 xmlXPathFreeObject(find);
6712}
6713
6714/**
6715 * xmlXPathNormalizeFunction:
6716 * @ctxt: the XPath Parser context
6717 * @nargs: the number of arguments
6718 *
6719 * Implement the normalize-space() XPath function
6720 * string normalize-space(string?)
6721 * The normalize-space function returns the argument string with white
6722 * space normalized by stripping leading and trailing whitespace
6723 * and replacing sequences of whitespace characters by a single
6724 * space. Whitespace characters are the same allowed by the S production
6725 * in XML. If the argument is omitted, it defaults to the context
6726 * node converted to a string, in other words the value of the context node.
6727 */
6728void
6729xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6730 xmlXPathObjectPtr obj = NULL;
6731 xmlChar *source = NULL;
6732 xmlBufferPtr target;
6733 xmlChar blank;
6734
6735 if (nargs == 0) {
6736 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006737 valuePush(ctxt,
6738 xmlXPathWrapString(
6739 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006740 nargs = 1;
6741 }
6742
6743 CHECK_ARITY(1);
6744 CAST_TO_STRING;
6745 CHECK_TYPE(XPATH_STRING);
6746 obj = valuePop(ctxt);
6747 source = obj->stringval;
6748
6749 target = xmlBufferCreate();
6750 if (target && source) {
6751
6752 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006753 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006754 source++;
6755
6756 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6757 blank = 0;
6758 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006759 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006760 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006761 } else {
6762 if (blank) {
6763 xmlBufferAdd(target, &blank, 1);
6764 blank = 0;
6765 }
6766 xmlBufferAdd(target, source, 1);
6767 }
6768 source++;
6769 }
6770
6771 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6772 xmlBufferFree(target);
6773 }
6774 xmlXPathFreeObject(obj);
6775}
6776
6777/**
6778 * xmlXPathTranslateFunction:
6779 * @ctxt: the XPath Parser context
6780 * @nargs: the number of arguments
6781 *
6782 * Implement the translate() XPath function
6783 * string translate(string, string, string)
6784 * The translate function returns the first argument string with
6785 * occurrences of characters in the second argument string replaced
6786 * by the character at the corresponding position in the third argument
6787 * string. For example, translate("bar","abc","ABC") returns the string
6788 * BAr. If there is a character in the second argument string with no
6789 * character at a corresponding position in the third argument string
6790 * (because the second argument string is longer than the third argument
6791 * string), then occurrences of that character in the first argument
6792 * string are removed. For example, translate("--aaa--","abc-","ABC")
6793 * returns "AAA". If a character occurs more than once in second
6794 * argument string, then the first occurrence determines the replacement
6795 * character. If the third argument string is longer than the second
6796 * argument string, then excess characters are ignored.
6797 */
6798void
6799xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006800 xmlXPathObjectPtr str;
6801 xmlXPathObjectPtr from;
6802 xmlXPathObjectPtr to;
6803 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006804 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006805 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006806 xmlChar *point;
6807 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006808
Daniel Veillarde043ee12001-04-16 14:08:07 +00006809 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006810
Daniel Veillarde043ee12001-04-16 14:08:07 +00006811 CAST_TO_STRING;
6812 to = valuePop(ctxt);
6813 CAST_TO_STRING;
6814 from = valuePop(ctxt);
6815 CAST_TO_STRING;
6816 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006817
Daniel Veillarde043ee12001-04-16 14:08:07 +00006818 target = xmlBufferCreate();
6819 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006820 max = xmlUTF8Strlen(to->stringval);
6821 for (cptr = str->stringval; (ch=*cptr); ) {
6822 offset = xmlUTF8Strloc(from->stringval, cptr);
6823 if (offset >= 0) {
6824 if (offset < max) {
6825 point = xmlUTF8Strpos(to->stringval, offset);
6826 if (point)
6827 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6828 }
6829 } else
6830 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6831
6832 /* Step to next character in input */
6833 cptr++;
6834 if ( ch & 0x80 ) {
6835 /* if not simple ascii, verify proper format */
6836 if ( (ch & 0xc0) != 0xc0 ) {
6837 xmlGenericError(xmlGenericErrorContext,
6838 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6839 break;
6840 }
6841 /* then skip over remaining bytes for this char */
6842 while ( (ch <<= 1) & 0x80 )
6843 if ( (*cptr++ & 0xc0) != 0x80 ) {
6844 xmlGenericError(xmlGenericErrorContext,
6845 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6846 break;
6847 }
6848 if (ch & 0x80) /* must have had error encountered */
6849 break;
6850 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006851 }
Owen Taylor3473f882001-02-23 17:55:21 +00006852 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006853 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6854 xmlBufferFree(target);
6855 xmlXPathFreeObject(str);
6856 xmlXPathFreeObject(from);
6857 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006858}
6859
6860/**
6861 * xmlXPathBooleanFunction:
6862 * @ctxt: the XPath Parser context
6863 * @nargs: the number of arguments
6864 *
6865 * Implement the boolean() XPath function
6866 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00006867 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006868 * - a number is true if and only if it is neither positive or
6869 * negative zero nor NaN
6870 * - a node-set is true if and only if it is non-empty
6871 * - a string is true if and only if its length is non-zero
6872 */
6873void
6874xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6875 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006876
6877 CHECK_ARITY(1);
6878 cur = valuePop(ctxt);
6879 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006880 cur = xmlXPathConvertBoolean(cur);
6881 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006882}
6883
6884/**
6885 * xmlXPathNotFunction:
6886 * @ctxt: the XPath Parser context
6887 * @nargs: the number of arguments
6888 *
6889 * Implement the not() XPath function
6890 * boolean not(boolean)
6891 * The not function returns true if its argument is false,
6892 * and false otherwise.
6893 */
6894void
6895xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6896 CHECK_ARITY(1);
6897 CAST_TO_BOOLEAN;
6898 CHECK_TYPE(XPATH_BOOLEAN);
6899 ctxt->value->boolval = ! ctxt->value->boolval;
6900}
6901
6902/**
6903 * xmlXPathTrueFunction:
6904 * @ctxt: the XPath Parser context
6905 * @nargs: the number of arguments
6906 *
6907 * Implement the true() XPath function
6908 * boolean true()
6909 */
6910void
6911xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6912 CHECK_ARITY(0);
6913 valuePush(ctxt, xmlXPathNewBoolean(1));
6914}
6915
6916/**
6917 * xmlXPathFalseFunction:
6918 * @ctxt: the XPath Parser context
6919 * @nargs: the number of arguments
6920 *
6921 * Implement the false() XPath function
6922 * boolean false()
6923 */
6924void
6925xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6926 CHECK_ARITY(0);
6927 valuePush(ctxt, xmlXPathNewBoolean(0));
6928}
6929
6930/**
6931 * xmlXPathLangFunction:
6932 * @ctxt: the XPath Parser context
6933 * @nargs: the number of arguments
6934 *
6935 * Implement the lang() XPath function
6936 * boolean lang(string)
6937 * The lang function returns true or false depending on whether the
6938 * language of the context node as specified by xml:lang attributes
6939 * is the same as or is a sublanguage of the language specified by
6940 * the argument string. The language of the context node is determined
6941 * by the value of the xml:lang attribute on the context node, or, if
6942 * the context node has no xml:lang attribute, by the value of the
6943 * xml:lang attribute on the nearest ancestor of the context node that
6944 * has an xml:lang attribute. If there is no such attribute, then lang
6945 * returns false. If there is such an attribute, then lang returns
6946 * true if the attribute value is equal to the argument ignoring case,
6947 * or if there is some suffix starting with - such that the attribute
6948 * value is equal to the argument ignoring that suffix of the attribute
6949 * value and ignoring case.
6950 */
6951void
6952xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6953 xmlXPathObjectPtr val;
6954 const xmlChar *theLang;
6955 const xmlChar *lang;
6956 int ret = 0;
6957 int i;
6958
6959 CHECK_ARITY(1);
6960 CAST_TO_STRING;
6961 CHECK_TYPE(XPATH_STRING);
6962 val = valuePop(ctxt);
6963 lang = val->stringval;
6964 theLang = xmlNodeGetLang(ctxt->context->node);
6965 if ((theLang != NULL) && (lang != NULL)) {
6966 for (i = 0;lang[i] != 0;i++)
6967 if (toupper(lang[i]) != toupper(theLang[i]))
6968 goto not_equal;
6969 ret = 1;
6970 }
6971not_equal:
6972 xmlXPathFreeObject(val);
6973 valuePush(ctxt, xmlXPathNewBoolean(ret));
6974}
6975
6976/**
6977 * xmlXPathNumberFunction:
6978 * @ctxt: the XPath Parser context
6979 * @nargs: the number of arguments
6980 *
6981 * Implement the number() XPath function
6982 * number number(object?)
6983 */
6984void
6985xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6986 xmlXPathObjectPtr cur;
6987 double res;
6988
6989 if (nargs == 0) {
6990 if (ctxt->context->node == NULL) {
6991 valuePush(ctxt, xmlXPathNewFloat(0.0));
6992 } else {
6993 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6994
6995 res = xmlXPathStringEvalNumber(content);
6996 valuePush(ctxt, xmlXPathNewFloat(res));
6997 xmlFree(content);
6998 }
6999 return;
7000 }
7001
7002 CHECK_ARITY(1);
7003 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007004 cur = xmlXPathConvertNumber(cur);
7005 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007006}
7007
7008/**
7009 * xmlXPathSumFunction:
7010 * @ctxt: the XPath Parser context
7011 * @nargs: the number of arguments
7012 *
7013 * Implement the sum() XPath function
7014 * number sum(node-set)
7015 * The sum function returns the sum of the values of the nodes in
7016 * the argument node-set.
7017 */
7018void
7019xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7020 xmlXPathObjectPtr cur;
7021 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007022 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007023
7024 CHECK_ARITY(1);
7025 if ((ctxt->value == NULL) ||
7026 ((ctxt->value->type != XPATH_NODESET) &&
7027 (ctxt->value->type != XPATH_XSLT_TREE)))
7028 XP_ERROR(XPATH_INVALID_TYPE);
7029 cur = valuePop(ctxt);
7030
William M. Brack08171912003-12-29 02:52:11 +00007031 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007032 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7033 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007034 }
7035 }
William M. Brack08171912003-12-29 02:52:11 +00007036 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007037 xmlXPathFreeObject(cur);
7038}
7039
7040/**
7041 * xmlXPathFloorFunction:
7042 * @ctxt: the XPath Parser context
7043 * @nargs: the number of arguments
7044 *
7045 * Implement the floor() XPath function
7046 * number floor(number)
7047 * The floor function returns the largest (closest to positive infinity)
7048 * number that is not greater than the argument and that is an integer.
7049 */
7050void
7051xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007052 double f;
7053
Owen Taylor3473f882001-02-23 17:55:21 +00007054 CHECK_ARITY(1);
7055 CAST_TO_NUMBER;
7056 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007057
7058 f = (double)((int) ctxt->value->floatval);
7059 if (f != ctxt->value->floatval) {
7060 if (ctxt->value->floatval > 0)
7061 ctxt->value->floatval = f;
7062 else
7063 ctxt->value->floatval = f - 1;
7064 }
Owen Taylor3473f882001-02-23 17:55:21 +00007065}
7066
7067/**
7068 * xmlXPathCeilingFunction:
7069 * @ctxt: the XPath Parser context
7070 * @nargs: the number of arguments
7071 *
7072 * Implement the ceiling() XPath function
7073 * number ceiling(number)
7074 * The ceiling function returns the smallest (closest to negative infinity)
7075 * number that is not less than the argument and that is an integer.
7076 */
7077void
7078xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7079 double f;
7080
7081 CHECK_ARITY(1);
7082 CAST_TO_NUMBER;
7083 CHECK_TYPE(XPATH_NUMBER);
7084
7085#if 0
7086 ctxt->value->floatval = ceil(ctxt->value->floatval);
7087#else
7088 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007089 if (f != ctxt->value->floatval) {
7090 if (ctxt->value->floatval > 0)
7091 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007092 else {
7093 if (ctxt->value->floatval < 0 && f == 0)
7094 ctxt->value->floatval = xmlXPathNZERO;
7095 else
7096 ctxt->value->floatval = f;
7097 }
7098
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007099 }
Owen Taylor3473f882001-02-23 17:55:21 +00007100#endif
7101}
7102
7103/**
7104 * xmlXPathRoundFunction:
7105 * @ctxt: the XPath Parser context
7106 * @nargs: the number of arguments
7107 *
7108 * Implement the round() XPath function
7109 * number round(number)
7110 * The round function returns the number that is closest to the
7111 * argument and that is an integer. If there are two such numbers,
7112 * then the one that is even is returned.
7113 */
7114void
7115xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7116 double f;
7117
7118 CHECK_ARITY(1);
7119 CAST_TO_NUMBER;
7120 CHECK_TYPE(XPATH_NUMBER);
7121
Daniel Veillardcda96922001-08-21 10:56:31 +00007122 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7123 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7124 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007125 (ctxt->value->floatval == 0.0))
7126 return;
7127
Owen Taylor3473f882001-02-23 17:55:21 +00007128 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007129 if (ctxt->value->floatval < 0) {
7130 if (ctxt->value->floatval < f - 0.5)
7131 ctxt->value->floatval = f - 1;
7132 else
7133 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007134 if (ctxt->value->floatval == 0)
7135 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007136 } else {
7137 if (ctxt->value->floatval < f + 0.5)
7138 ctxt->value->floatval = f;
7139 else
7140 ctxt->value->floatval = f + 1;
7141 }
Owen Taylor3473f882001-02-23 17:55:21 +00007142}
7143
7144/************************************************************************
7145 * *
7146 * The Parser *
7147 * *
7148 ************************************************************************/
7149
7150/*
William M. Brack08171912003-12-29 02:52:11 +00007151 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007152 * implementation.
7153 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007154static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007155static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007156static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007157static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007158static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7159 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007160
7161/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007162 * xmlXPathCurrentChar:
7163 * @ctxt: the XPath parser context
7164 * @cur: pointer to the beginning of the char
7165 * @len: pointer to the length of the char read
7166 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007167 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007168 * bytes in the input buffer.
7169 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007170 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007171 */
7172
7173static int
7174xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7175 unsigned char c;
7176 unsigned int val;
7177 const xmlChar *cur;
7178
7179 if (ctxt == NULL)
7180 return(0);
7181 cur = ctxt->cur;
7182
7183 /*
7184 * We are supposed to handle UTF8, check it's valid
7185 * From rfc2044: encoding of the Unicode values on UTF-8:
7186 *
7187 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7188 * 0000 0000-0000 007F 0xxxxxxx
7189 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7190 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7191 *
7192 * Check for the 0x110000 limit too
7193 */
7194 c = *cur;
7195 if (c & 0x80) {
7196 if ((cur[1] & 0xc0) != 0x80)
7197 goto encoding_error;
7198 if ((c & 0xe0) == 0xe0) {
7199
7200 if ((cur[2] & 0xc0) != 0x80)
7201 goto encoding_error;
7202 if ((c & 0xf0) == 0xf0) {
7203 if (((c & 0xf8) != 0xf0) ||
7204 ((cur[3] & 0xc0) != 0x80))
7205 goto encoding_error;
7206 /* 4-byte code */
7207 *len = 4;
7208 val = (cur[0] & 0x7) << 18;
7209 val |= (cur[1] & 0x3f) << 12;
7210 val |= (cur[2] & 0x3f) << 6;
7211 val |= cur[3] & 0x3f;
7212 } else {
7213 /* 3-byte code */
7214 *len = 3;
7215 val = (cur[0] & 0xf) << 12;
7216 val |= (cur[1] & 0x3f) << 6;
7217 val |= cur[2] & 0x3f;
7218 }
7219 } else {
7220 /* 2-byte code */
7221 *len = 2;
7222 val = (cur[0] & 0x1f) << 6;
7223 val |= cur[1] & 0x3f;
7224 }
7225 if (!IS_CHAR(val)) {
7226 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7227 }
7228 return(val);
7229 } else {
7230 /* 1-byte code */
7231 *len = 1;
7232 return((int) *cur);
7233 }
7234encoding_error:
7235 /*
William M. Brack08171912003-12-29 02:52:11 +00007236 * If we detect an UTF8 error that probably means that the
7237 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007238 * declaration header. Report the error and switch the encoding
7239 * to ISO-Latin-1 (if you don't like this policy, just declare the
7240 * encoding !)
7241 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007242 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007243 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007244}
7245
7246/**
Owen Taylor3473f882001-02-23 17:55:21 +00007247 * xmlXPathParseNCName:
7248 * @ctxt: the XPath Parser context
7249 *
7250 * parse an XML namespace non qualified name.
7251 *
7252 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7253 *
7254 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7255 * CombiningChar | Extender
7256 *
7257 * Returns the namespace name or NULL
7258 */
7259
7260xmlChar *
7261xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007262 const xmlChar *in;
7263 xmlChar *ret;
7264 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007265
Daniel Veillard2156a562001-04-28 12:24:34 +00007266 /*
7267 * Accelerator for simple ASCII names
7268 */
7269 in = ctxt->cur;
7270 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7271 ((*in >= 0x41) && (*in <= 0x5A)) ||
7272 (*in == '_')) {
7273 in++;
7274 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7275 ((*in >= 0x41) && (*in <= 0x5A)) ||
7276 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007277 (*in == '_') || (*in == '.') ||
7278 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007279 in++;
7280 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7281 (*in == '[') || (*in == ']') || (*in == ':') ||
7282 (*in == '@') || (*in == '*')) {
7283 count = in - ctxt->cur;
7284 if (count == 0)
7285 return(NULL);
7286 ret = xmlStrndup(ctxt->cur, count);
7287 ctxt->cur = in;
7288 return(ret);
7289 }
7290 }
7291 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007292}
7293
Daniel Veillard2156a562001-04-28 12:24:34 +00007294
Owen Taylor3473f882001-02-23 17:55:21 +00007295/**
7296 * xmlXPathParseQName:
7297 * @ctxt: the XPath Parser context
7298 * @prefix: a xmlChar **
7299 *
7300 * parse an XML qualified name
7301 *
7302 * [NS 5] QName ::= (Prefix ':')? LocalPart
7303 *
7304 * [NS 6] Prefix ::= NCName
7305 *
7306 * [NS 7] LocalPart ::= NCName
7307 *
7308 * Returns the function returns the local part, and prefix is updated
7309 * to get the Prefix if any.
7310 */
7311
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007312static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007313xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7314 xmlChar *ret = NULL;
7315
7316 *prefix = NULL;
7317 ret = xmlXPathParseNCName(ctxt);
7318 if (CUR == ':') {
7319 *prefix = ret;
7320 NEXT;
7321 ret = xmlXPathParseNCName(ctxt);
7322 }
7323 return(ret);
7324}
7325
7326/**
7327 * xmlXPathParseName:
7328 * @ctxt: the XPath Parser context
7329 *
7330 * parse an XML name
7331 *
7332 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7333 * CombiningChar | Extender
7334 *
7335 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7336 *
7337 * Returns the namespace name or NULL
7338 */
7339
7340xmlChar *
7341xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007342 const xmlChar *in;
7343 xmlChar *ret;
7344 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007345
Daniel Veillard61d80a22001-04-27 17:13:01 +00007346 /*
7347 * Accelerator for simple ASCII names
7348 */
7349 in = ctxt->cur;
7350 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7351 ((*in >= 0x41) && (*in <= 0x5A)) ||
7352 (*in == '_') || (*in == ':')) {
7353 in++;
7354 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7355 ((*in >= 0x41) && (*in <= 0x5A)) ||
7356 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007357 (*in == '_') || (*in == '-') ||
7358 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007359 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007360 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007361 count = in - ctxt->cur;
7362 ret = xmlStrndup(ctxt->cur, count);
7363 ctxt->cur = in;
7364 return(ret);
7365 }
7366 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007367 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007368}
7369
Daniel Veillard61d80a22001-04-27 17:13:01 +00007370static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007371xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007372 xmlChar buf[XML_MAX_NAMELEN + 5];
7373 int len = 0, l;
7374 int c;
7375
7376 /*
7377 * Handler for more complex cases
7378 */
7379 c = CUR_CHAR(l);
7380 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007381 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7382 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007383 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007384 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007385 return(NULL);
7386 }
7387
7388 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7389 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7390 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007391 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007392 (IS_COMBINING(c)) ||
7393 (IS_EXTENDER(c)))) {
7394 COPY_BUF(l,buf,len,c);
7395 NEXTL(l);
7396 c = CUR_CHAR(l);
7397 if (len >= XML_MAX_NAMELEN) {
7398 /*
7399 * Okay someone managed to make a huge name, so he's ready to pay
7400 * for the processing speed.
7401 */
7402 xmlChar *buffer;
7403 int max = len * 2;
7404
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007405 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007406 if (buffer == NULL) {
7407 XP_ERROR0(XPATH_MEMORY_ERROR);
7408 }
7409 memcpy(buffer, buf, len);
7410 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7411 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007412 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007413 (IS_COMBINING(c)) ||
7414 (IS_EXTENDER(c))) {
7415 if (len + 10 > max) {
7416 max *= 2;
7417 buffer = (xmlChar *) xmlRealloc(buffer,
7418 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007419 if (buffer == NULL) {
7420 XP_ERROR0(XPATH_MEMORY_ERROR);
7421 }
7422 }
7423 COPY_BUF(l,buffer,len,c);
7424 NEXTL(l);
7425 c = CUR_CHAR(l);
7426 }
7427 buffer[len] = 0;
7428 return(buffer);
7429 }
7430 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007431 if (len == 0)
7432 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007433 return(xmlStrndup(buf, len));
7434}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007435
7436#define MAX_FRAC 20
7437
7438static double my_pow10[MAX_FRAC] = {
7439 1.0, 10.0, 100.0, 1000.0, 10000.0,
7440 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7441 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7442 100000000000000.0,
7443 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7444 1000000000000000000.0, 10000000000000000000.0
7445};
7446
Owen Taylor3473f882001-02-23 17:55:21 +00007447/**
7448 * xmlXPathStringEvalNumber:
7449 * @str: A string to scan
7450 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007451 * [30a] Float ::= Number ('e' Digits?)?
7452 *
Owen Taylor3473f882001-02-23 17:55:21 +00007453 * [30] Number ::= Digits ('.' Digits?)?
7454 * | '.' Digits
7455 * [31] Digits ::= [0-9]+
7456 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007457 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007458 * In complement of the Number expression, this function also handles
7459 * negative values : '-' Number.
7460 *
7461 * Returns the double value.
7462 */
7463double
7464xmlXPathStringEvalNumber(const xmlChar *str) {
7465 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007466 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007467 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007468 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007469 int exponent = 0;
7470 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007471#ifdef __GNUC__
7472 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007473 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007474#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007475 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007476 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007477 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7478 return(xmlXPathNAN);
7479 }
7480 if (*cur == '-') {
7481 isneg = 1;
7482 cur++;
7483 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007484
7485#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007486 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007487 * tmp/temp is a workaround against a gcc compiler bug
7488 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007489 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007490 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007491 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007492 ret = ret * 10;
7493 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007494 ok = 1;
7495 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007496 temp = (double) tmp;
7497 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007498 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007499#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007500 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007501 while ((*cur >= '0') && (*cur <= '9')) {
7502 ret = ret * 10 + (*cur - '0');
7503 ok = 1;
7504 cur++;
7505 }
7506#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007507
Owen Taylor3473f882001-02-23 17:55:21 +00007508 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007509 int v, frac = 0;
7510 double fraction = 0;
7511
Owen Taylor3473f882001-02-23 17:55:21 +00007512 cur++;
7513 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7514 return(xmlXPathNAN);
7515 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007516 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7517 v = (*cur - '0');
7518 fraction = fraction * 10 + v;
7519 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007520 cur++;
7521 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007522 fraction /= my_pow10[frac];
7523 ret = ret + fraction;
7524 while ((*cur >= '0') && (*cur <= '9'))
7525 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007526 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007527 if ((*cur == 'e') || (*cur == 'E')) {
7528 cur++;
7529 if (*cur == '-') {
7530 is_exponent_negative = 1;
7531 cur++;
7532 }
7533 while ((*cur >= '0') && (*cur <= '9')) {
7534 exponent = exponent * 10 + (*cur - '0');
7535 cur++;
7536 }
7537 }
William M. Brack76e95df2003-10-18 16:20:14 +00007538 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007539 if (*cur != 0) return(xmlXPathNAN);
7540 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007541 if (is_exponent_negative) exponent = -exponent;
7542 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007543 return(ret);
7544}
7545
7546/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007547 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007548 * @ctxt: the XPath Parser context
7549 *
7550 * [30] Number ::= Digits ('.' Digits?)?
7551 * | '.' Digits
7552 * [31] Digits ::= [0-9]+
7553 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007554 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007555 *
7556 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007557static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007558xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7559{
Owen Taylor3473f882001-02-23 17:55:21 +00007560 double ret = 0.0;
7561 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007562 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007563 int exponent = 0;
7564 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007565#ifdef __GNUC__
7566 unsigned long tmp = 0;
7567 double temp;
7568#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007569
7570 CHECK_ERROR;
7571 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7572 XP_ERROR(XPATH_NUMBER_ERROR);
7573 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007574#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007575 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007576 * tmp/temp is a workaround against a gcc compiler bug
7577 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007578 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007579 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007580 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007581 ret = ret * 10;
7582 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007583 ok = 1;
7584 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007585 temp = (double) tmp;
7586 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007587 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007588#else
7589 ret = 0;
7590 while ((CUR >= '0') && (CUR <= '9')) {
7591 ret = ret * 10 + (CUR - '0');
7592 ok = 1;
7593 NEXT;
7594 }
7595#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007596 if (CUR == '.') {
7597 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007598 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7599 XP_ERROR(XPATH_NUMBER_ERROR);
7600 }
7601 while ((CUR >= '0') && (CUR <= '9')) {
7602 mult /= 10;
7603 ret = ret + (CUR - '0') * mult;
7604 NEXT;
7605 }
Owen Taylor3473f882001-02-23 17:55:21 +00007606 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007607 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007608 NEXT;
7609 if (CUR == '-') {
7610 is_exponent_negative = 1;
7611 NEXT;
7612 }
7613 while ((CUR >= '0') && (CUR <= '9')) {
7614 exponent = exponent * 10 + (CUR - '0');
7615 NEXT;
7616 }
7617 if (is_exponent_negative)
7618 exponent = -exponent;
7619 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007620 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007621 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007622 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007623}
7624
7625/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007626 * xmlXPathParseLiteral:
7627 * @ctxt: the XPath Parser context
7628 *
7629 * Parse a Literal
7630 *
7631 * [29] Literal ::= '"' [^"]* '"'
7632 * | "'" [^']* "'"
7633 *
7634 * Returns the value found or NULL in case of error
7635 */
7636static xmlChar *
7637xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7638 const xmlChar *q;
7639 xmlChar *ret = NULL;
7640
7641 if (CUR == '"') {
7642 NEXT;
7643 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007644 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007645 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007646 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007647 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7648 } else {
7649 ret = xmlStrndup(q, CUR_PTR - q);
7650 NEXT;
7651 }
7652 } else if (CUR == '\'') {
7653 NEXT;
7654 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007655 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007656 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007657 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007658 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7659 } else {
7660 ret = xmlStrndup(q, CUR_PTR - q);
7661 NEXT;
7662 }
7663 } else {
7664 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7665 }
7666 return(ret);
7667}
7668
7669/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007670 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007671 * @ctxt: the XPath Parser context
7672 *
7673 * Parse a Literal and push it on the stack.
7674 *
7675 * [29] Literal ::= '"' [^"]* '"'
7676 * | "'" [^']* "'"
7677 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007678 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007679 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007680static void
7681xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007682 const xmlChar *q;
7683 xmlChar *ret = NULL;
7684
7685 if (CUR == '"') {
7686 NEXT;
7687 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007688 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007689 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007690 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007691 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7692 } else {
7693 ret = xmlStrndup(q, CUR_PTR - q);
7694 NEXT;
7695 }
7696 } else if (CUR == '\'') {
7697 NEXT;
7698 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007699 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007700 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007701 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007702 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7703 } else {
7704 ret = xmlStrndup(q, CUR_PTR - q);
7705 NEXT;
7706 }
7707 } else {
7708 XP_ERROR(XPATH_START_LITERAL_ERROR);
7709 }
7710 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007711 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7712 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007713 xmlFree(ret);
7714}
7715
7716/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007717 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007718 * @ctxt: the XPath Parser context
7719 *
7720 * Parse a VariableReference, evaluate it and push it on the stack.
7721 *
7722 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00007723 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00007724 * of any of the types that are possible for the value of an expression,
7725 * and may also be of additional types not specified here.
7726 *
7727 * Early evaluation is possible since:
7728 * The variable bindings [...] used to evaluate a subexpression are
7729 * always the same as those used to evaluate the containing expression.
7730 *
7731 * [36] VariableReference ::= '$' QName
7732 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007733static void
7734xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007735 xmlChar *name;
7736 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007737
7738 SKIP_BLANKS;
7739 if (CUR != '$') {
7740 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7741 }
7742 NEXT;
7743 name = xmlXPathParseQName(ctxt, &prefix);
7744 if (name == NULL) {
7745 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7746 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007747 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007748 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7749 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007750 SKIP_BLANKS;
7751}
7752
7753/**
7754 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007755 * @name: a name string
7756 *
7757 * Is the name given a NodeType one.
7758 *
7759 * [38] NodeType ::= 'comment'
7760 * | 'text'
7761 * | 'processing-instruction'
7762 * | 'node'
7763 *
7764 * Returns 1 if true 0 otherwise
7765 */
7766int
7767xmlXPathIsNodeType(const xmlChar *name) {
7768 if (name == NULL)
7769 return(0);
7770
Daniel Veillard1971ee22002-01-31 20:29:19 +00007771 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007772 return(1);
7773 if (xmlStrEqual(name, BAD_CAST "text"))
7774 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007775 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007776 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007777 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007778 return(1);
7779 return(0);
7780}
7781
7782/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007783 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007784 * @ctxt: the XPath Parser context
7785 *
7786 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7787 * [17] Argument ::= Expr
7788 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007789 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007790 * pushed on the stack
7791 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007792static void
7793xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007794 xmlChar *name;
7795 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007796 int nbargs = 0;
7797
7798 name = xmlXPathParseQName(ctxt, &prefix);
7799 if (name == NULL) {
7800 XP_ERROR(XPATH_EXPR_ERROR);
7801 }
7802 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007803#ifdef DEBUG_EXPR
7804 if (prefix == NULL)
7805 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7806 name);
7807 else
7808 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7809 prefix, name);
7810#endif
7811
Owen Taylor3473f882001-02-23 17:55:21 +00007812 if (CUR != '(') {
7813 XP_ERROR(XPATH_EXPR_ERROR);
7814 }
7815 NEXT;
7816 SKIP_BLANKS;
7817
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007818 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007819 if (CUR != ')') {
7820 while (CUR != 0) {
7821 int op1 = ctxt->comp->last;
7822 ctxt->comp->last = -1;
7823 xmlXPathCompileExpr(ctxt);
7824 CHECK_ERROR;
7825 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7826 nbargs++;
7827 if (CUR == ')') break;
7828 if (CUR != ',') {
7829 XP_ERROR(XPATH_EXPR_ERROR);
7830 }
7831 NEXT;
7832 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007833 }
Owen Taylor3473f882001-02-23 17:55:21 +00007834 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007835 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7836 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007837 NEXT;
7838 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007839}
7840
7841/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007842 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007843 * @ctxt: the XPath Parser context
7844 *
7845 * [15] PrimaryExpr ::= VariableReference
7846 * | '(' Expr ')'
7847 * | Literal
7848 * | Number
7849 * | FunctionCall
7850 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007851 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007852 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007853static void
7854xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007855 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007856 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007857 else if (CUR == '(') {
7858 NEXT;
7859 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007860 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007861 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007862 if (CUR != ')') {
7863 XP_ERROR(XPATH_EXPR_ERROR);
7864 }
7865 NEXT;
7866 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007867 } else if (IS_DIGIT_CH(CUR) || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007868 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007869 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007870 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007871 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007872 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007873 }
7874 SKIP_BLANKS;
7875}
7876
7877/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007878 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007879 * @ctxt: the XPath Parser context
7880 *
7881 * [20] FilterExpr ::= PrimaryExpr
7882 * | FilterExpr Predicate
7883 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007884 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007885 * Square brackets are used to filter expressions in the same way that
7886 * they are used in location paths. It is an error if the expression to
7887 * be filtered does not evaluate to a node-set. The context node list
7888 * used for evaluating the expression in square brackets is the node-set
7889 * to be filtered listed in document order.
7890 */
7891
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007892static void
7893xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7894 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007895 CHECK_ERROR;
7896 SKIP_BLANKS;
7897
7898 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007899 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007900 SKIP_BLANKS;
7901 }
7902
7903
7904}
7905
7906/**
7907 * xmlXPathScanName:
7908 * @ctxt: the XPath Parser context
7909 *
7910 * Trickery: parse an XML name but without consuming the input flow
7911 * Needed to avoid insanity in the parser state.
7912 *
7913 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7914 * CombiningChar | Extender
7915 *
7916 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7917 *
7918 * [6] Names ::= Name (S Name)*
7919 *
7920 * Returns the Name parsed or NULL
7921 */
7922
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007923static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007924xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7925 xmlChar buf[XML_MAX_NAMELEN];
7926 int len = 0;
7927
7928 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007929 if (!IS_LETTER_CH(CUR) && (CUR != '_') &&
Owen Taylor3473f882001-02-23 17:55:21 +00007930 (CUR != ':')) {
7931 return(NULL);
7932 }
7933
William M. Brack76e95df2003-10-18 16:20:14 +00007934 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007935 (NXT(len) == '.') || (NXT(len) == '-') ||
7936 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00007937 (IS_COMBINING_CH(NXT(len))) ||
7938 (IS_EXTENDER_CH(NXT(len)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007939 buf[len] = NXT(len);
7940 len++;
7941 if (len >= XML_MAX_NAMELEN) {
7942 xmlGenericError(xmlGenericErrorContext,
7943 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
William M. Brack76e95df2003-10-18 16:20:14 +00007944 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007945 (NXT(len) == '.') || (NXT(len) == '-') ||
7946 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00007947 (IS_COMBINING_CH(NXT(len))) ||
7948 (IS_EXTENDER_CH(NXT(len))))
Owen Taylor3473f882001-02-23 17:55:21 +00007949 len++;
7950 break;
7951 }
7952 }
7953 return(xmlStrndup(buf, len));
7954}
7955
7956/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007957 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007958 * @ctxt: the XPath Parser context
7959 *
7960 * [19] PathExpr ::= LocationPath
7961 * | FilterExpr
7962 * | FilterExpr '/' RelativeLocationPath
7963 * | FilterExpr '//' RelativeLocationPath
7964 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007965 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007966 * The / operator and // operators combine an arbitrary expression
7967 * and a relative location path. It is an error if the expression
7968 * does not evaluate to a node-set.
7969 * The / operator does composition in the same way as when / is
7970 * used in a location path. As in location paths, // is short for
7971 * /descendant-or-self::node()/.
7972 */
7973
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007974static void
7975xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007976 int lc = 1; /* Should we branch to LocationPath ? */
7977 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7978
7979 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007980 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT_CH(CUR)) ||
7981 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00007982 lc = 0;
7983 } else if (CUR == '*') {
7984 /* relative or absolute location path */
7985 lc = 1;
7986 } else if (CUR == '/') {
7987 /* relative or absolute location path */
7988 lc = 1;
7989 } else if (CUR == '@') {
7990 /* relative abbreviated attribute location path */
7991 lc = 1;
7992 } else if (CUR == '.') {
7993 /* relative abbreviated attribute location path */
7994 lc = 1;
7995 } else {
7996 /*
7997 * Problem is finding if we have a name here whether it's:
7998 * - a nodetype
7999 * - a function call in which case it's followed by '('
8000 * - an axis in which case it's followed by ':'
8001 * - a element name
8002 * We do an a priori analysis here rather than having to
8003 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008004 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008005 * read/write/debug.
8006 */
8007 SKIP_BLANKS;
8008 name = xmlXPathScanName(ctxt);
8009 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8010#ifdef DEBUG_STEP
8011 xmlGenericError(xmlGenericErrorContext,
8012 "PathExpr: Axis\n");
8013#endif
8014 lc = 1;
8015 xmlFree(name);
8016 } else if (name != NULL) {
8017 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008018
8019
8020 while (NXT(len) != 0) {
8021 if (NXT(len) == '/') {
8022 /* element name */
8023#ifdef DEBUG_STEP
8024 xmlGenericError(xmlGenericErrorContext,
8025 "PathExpr: AbbrRelLocation\n");
8026#endif
8027 lc = 1;
8028 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008029 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008030 /* ignore blanks */
8031 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008032 } else if (NXT(len) == ':') {
8033#ifdef DEBUG_STEP
8034 xmlGenericError(xmlGenericErrorContext,
8035 "PathExpr: AbbrRelLocation\n");
8036#endif
8037 lc = 1;
8038 break;
8039 } else if ((NXT(len) == '(')) {
8040 /* Note Type or Function */
8041 if (xmlXPathIsNodeType(name)) {
8042#ifdef DEBUG_STEP
8043 xmlGenericError(xmlGenericErrorContext,
8044 "PathExpr: Type search\n");
8045#endif
8046 lc = 1;
8047 } else {
8048#ifdef DEBUG_STEP
8049 xmlGenericError(xmlGenericErrorContext,
8050 "PathExpr: function call\n");
8051#endif
8052 lc = 0;
8053 }
8054 break;
8055 } else if ((NXT(len) == '[')) {
8056 /* element name */
8057#ifdef DEBUG_STEP
8058 xmlGenericError(xmlGenericErrorContext,
8059 "PathExpr: AbbrRelLocation\n");
8060#endif
8061 lc = 1;
8062 break;
8063 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8064 (NXT(len) == '=')) {
8065 lc = 1;
8066 break;
8067 } else {
8068 lc = 1;
8069 break;
8070 }
8071 len++;
8072 }
8073 if (NXT(len) == 0) {
8074#ifdef DEBUG_STEP
8075 xmlGenericError(xmlGenericErrorContext,
8076 "PathExpr: AbbrRelLocation\n");
8077#endif
8078 /* element name */
8079 lc = 1;
8080 }
8081 xmlFree(name);
8082 } else {
William M. Brack08171912003-12-29 02:52:11 +00008083 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008084 XP_ERROR(XPATH_EXPR_ERROR);
8085 }
8086 }
8087
8088 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008089 if (CUR == '/') {
8090 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8091 } else {
8092 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008093 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008094 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008095 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008096 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008097 CHECK_ERROR;
8098 if ((CUR == '/') && (NXT(1) == '/')) {
8099 SKIP(2);
8100 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008101
8102 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8103 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8104 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8105
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008106 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008107 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008108 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008109 }
8110 }
8111 SKIP_BLANKS;
8112}
8113
8114/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008115 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008116 * @ctxt: the XPath Parser context
8117 *
8118 * [18] UnionExpr ::= PathExpr
8119 * | UnionExpr '|' PathExpr
8120 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008121 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008122 */
8123
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008124static void
8125xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8126 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008127 CHECK_ERROR;
8128 SKIP_BLANKS;
8129 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008130 int op1 = ctxt->comp->last;
8131 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008132
8133 NEXT;
8134 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008135 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008136
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008137 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8138
Owen Taylor3473f882001-02-23 17:55:21 +00008139 SKIP_BLANKS;
8140 }
Owen Taylor3473f882001-02-23 17:55:21 +00008141}
8142
8143/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008144 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008145 * @ctxt: the XPath Parser context
8146 *
8147 * [27] UnaryExpr ::= UnionExpr
8148 * | '-' UnaryExpr
8149 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008150 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008151 */
8152
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008153static void
8154xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008155 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008156 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008157
8158 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008159 while (CUR == '-') {
8160 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008161 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008162 NEXT;
8163 SKIP_BLANKS;
8164 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008165
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008166 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008167 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008168 if (found) {
8169 if (minus)
8170 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8171 else
8172 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008173 }
8174}
8175
8176/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008177 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008178 * @ctxt: the XPath Parser context
8179 *
8180 * [26] MultiplicativeExpr ::= UnaryExpr
8181 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8182 * | MultiplicativeExpr 'div' UnaryExpr
8183 * | MultiplicativeExpr 'mod' UnaryExpr
8184 * [34] MultiplyOperator ::= '*'
8185 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008186 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008187 */
8188
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008189static void
8190xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8191 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008192 CHECK_ERROR;
8193 SKIP_BLANKS;
8194 while ((CUR == '*') ||
8195 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8196 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8197 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008198 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008199
8200 if (CUR == '*') {
8201 op = 0;
8202 NEXT;
8203 } else if (CUR == 'd') {
8204 op = 1;
8205 SKIP(3);
8206 } else if (CUR == 'm') {
8207 op = 2;
8208 SKIP(3);
8209 }
8210 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008211 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008212 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008213 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008214 SKIP_BLANKS;
8215 }
8216}
8217
8218/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008219 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008220 * @ctxt: the XPath Parser context
8221 *
8222 * [25] AdditiveExpr ::= MultiplicativeExpr
8223 * | AdditiveExpr '+' MultiplicativeExpr
8224 * | AdditiveExpr '-' MultiplicativeExpr
8225 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008226 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008227 */
8228
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008229static void
8230xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008231
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008232 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008233 CHECK_ERROR;
8234 SKIP_BLANKS;
8235 while ((CUR == '+') || (CUR == '-')) {
8236 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008237 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008238
8239 if (CUR == '+') plus = 1;
8240 else plus = 0;
8241 NEXT;
8242 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008243 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008244 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008245 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008246 SKIP_BLANKS;
8247 }
8248}
8249
8250/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008251 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008252 * @ctxt: the XPath Parser context
8253 *
8254 * [24] RelationalExpr ::= AdditiveExpr
8255 * | RelationalExpr '<' AdditiveExpr
8256 * | RelationalExpr '>' AdditiveExpr
8257 * | RelationalExpr '<=' AdditiveExpr
8258 * | RelationalExpr '>=' AdditiveExpr
8259 *
8260 * A <= B > C is allowed ? Answer from James, yes with
8261 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8262 * which is basically what got implemented.
8263 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008264 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008265 * on the stack
8266 */
8267
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008268static void
8269xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8270 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008271 CHECK_ERROR;
8272 SKIP_BLANKS;
8273 while ((CUR == '<') ||
8274 (CUR == '>') ||
8275 ((CUR == '<') && (NXT(1) == '=')) ||
8276 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008277 int inf, strict;
8278 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008279
8280 if (CUR == '<') inf = 1;
8281 else inf = 0;
8282 if (NXT(1) == '=') strict = 0;
8283 else strict = 1;
8284 NEXT;
8285 if (!strict) NEXT;
8286 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008287 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008288 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008289 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008290 SKIP_BLANKS;
8291 }
8292}
8293
8294/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008295 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008296 * @ctxt: the XPath Parser context
8297 *
8298 * [23] EqualityExpr ::= RelationalExpr
8299 * | EqualityExpr '=' RelationalExpr
8300 * | EqualityExpr '!=' RelationalExpr
8301 *
8302 * A != B != C is allowed ? Answer from James, yes with
8303 * (RelationalExpr = RelationalExpr) = RelationalExpr
8304 * (RelationalExpr != RelationalExpr) != RelationalExpr
8305 * which is basically what got implemented.
8306 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008307 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008308 *
8309 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008310static void
8311xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8312 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008313 CHECK_ERROR;
8314 SKIP_BLANKS;
8315 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008316 int eq;
8317 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008318
8319 if (CUR == '=') eq = 1;
8320 else eq = 0;
8321 NEXT;
8322 if (!eq) NEXT;
8323 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008324 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008325 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008326 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008327 SKIP_BLANKS;
8328 }
8329}
8330
8331/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008332 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008333 * @ctxt: the XPath Parser context
8334 *
8335 * [22] AndExpr ::= EqualityExpr
8336 * | AndExpr 'and' EqualityExpr
8337 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008338 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008339 *
8340 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008341static void
8342xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8343 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008344 CHECK_ERROR;
8345 SKIP_BLANKS;
8346 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008347 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008348 SKIP(3);
8349 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008350 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008351 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008352 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008353 SKIP_BLANKS;
8354 }
8355}
8356
8357/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008358 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008359 * @ctxt: the XPath Parser context
8360 *
8361 * [14] Expr ::= OrExpr
8362 * [21] OrExpr ::= AndExpr
8363 * | OrExpr 'or' AndExpr
8364 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008365 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008366 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008367static void
8368xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8369 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008370 CHECK_ERROR;
8371 SKIP_BLANKS;
8372 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008373 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008374 SKIP(2);
8375 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008376 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008377 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008378 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8379 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008380 SKIP_BLANKS;
8381 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008382 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8383 /* more ops could be optimized too */
8384 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8385 }
Owen Taylor3473f882001-02-23 17:55:21 +00008386}
8387
8388/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008389 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008390 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008391 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008392 *
8393 * [8] Predicate ::= '[' PredicateExpr ']'
8394 * [9] PredicateExpr ::= Expr
8395 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008396 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008397 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008398static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008399xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008400 int op1 = ctxt->comp->last;
8401
8402 SKIP_BLANKS;
8403 if (CUR != '[') {
8404 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8405 }
8406 NEXT;
8407 SKIP_BLANKS;
8408
8409 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008410 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008411 CHECK_ERROR;
8412
8413 if (CUR != ']') {
8414 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8415 }
8416
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008417 if (filter)
8418 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8419 else
8420 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008421
8422 NEXT;
8423 SKIP_BLANKS;
8424}
8425
8426/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008427 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008428 * @ctxt: the XPath Parser context
8429 * @test: pointer to a xmlXPathTestVal
8430 * @type: pointer to a xmlXPathTypeVal
8431 * @prefix: placeholder for a possible name prefix
8432 *
8433 * [7] NodeTest ::= NameTest
8434 * | NodeType '(' ')'
8435 * | 'processing-instruction' '(' Literal ')'
8436 *
8437 * [37] NameTest ::= '*'
8438 * | NCName ':' '*'
8439 * | QName
8440 * [38] NodeType ::= 'comment'
8441 * | 'text'
8442 * | 'processing-instruction'
8443 * | 'node'
8444 *
William M. Brack08171912003-12-29 02:52:11 +00008445 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00008446 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008447static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008448xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8449 xmlXPathTypeVal *type, const xmlChar **prefix,
8450 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008451 int blanks;
8452
8453 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8454 STRANGE;
8455 return(NULL);
8456 }
William M. Brack78637da2003-07-31 14:47:38 +00008457 *type = (xmlXPathTypeVal) 0;
8458 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008459 *prefix = NULL;
8460 SKIP_BLANKS;
8461
8462 if ((name == NULL) && (CUR == '*')) {
8463 /*
8464 * All elements
8465 */
8466 NEXT;
8467 *test = NODE_TEST_ALL;
8468 return(NULL);
8469 }
8470
8471 if (name == NULL)
8472 name = xmlXPathParseNCName(ctxt);
8473 if (name == NULL) {
8474 XP_ERROR0(XPATH_EXPR_ERROR);
8475 }
8476
William M. Brack76e95df2003-10-18 16:20:14 +00008477 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008478 SKIP_BLANKS;
8479 if (CUR == '(') {
8480 NEXT;
8481 /*
8482 * NodeType or PI search
8483 */
8484 if (xmlStrEqual(name, BAD_CAST "comment"))
8485 *type = NODE_TYPE_COMMENT;
8486 else if (xmlStrEqual(name, BAD_CAST "node"))
8487 *type = NODE_TYPE_NODE;
8488 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8489 *type = NODE_TYPE_PI;
8490 else if (xmlStrEqual(name, BAD_CAST "text"))
8491 *type = NODE_TYPE_TEXT;
8492 else {
8493 if (name != NULL)
8494 xmlFree(name);
8495 XP_ERROR0(XPATH_EXPR_ERROR);
8496 }
8497
8498 *test = NODE_TEST_TYPE;
8499
8500 SKIP_BLANKS;
8501 if (*type == NODE_TYPE_PI) {
8502 /*
8503 * Specific case: search a PI by name.
8504 */
Owen Taylor3473f882001-02-23 17:55:21 +00008505 if (name != NULL)
8506 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008507 name = NULL;
8508 if (CUR != ')') {
8509 name = xmlXPathParseLiteral(ctxt);
8510 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008511 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008512 SKIP_BLANKS;
8513 }
Owen Taylor3473f882001-02-23 17:55:21 +00008514 }
8515 if (CUR != ')') {
8516 if (name != NULL)
8517 xmlFree(name);
8518 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8519 }
8520 NEXT;
8521 return(name);
8522 }
8523 *test = NODE_TEST_NAME;
8524 if ((!blanks) && (CUR == ':')) {
8525 NEXT;
8526
8527 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008528 * Since currently the parser context don't have a
8529 * namespace list associated:
8530 * The namespace name for this prefix can be computed
8531 * only at evaluation time. The compilation is done
8532 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008533 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008534#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008535 *prefix = xmlXPathNsLookup(ctxt->context, name);
8536 if (name != NULL)
8537 xmlFree(name);
8538 if (*prefix == NULL) {
8539 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8540 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008541#else
8542 *prefix = name;
8543#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008544
8545 if (CUR == '*') {
8546 /*
8547 * All elements
8548 */
8549 NEXT;
8550 *test = NODE_TEST_ALL;
8551 return(NULL);
8552 }
8553
8554 name = xmlXPathParseNCName(ctxt);
8555 if (name == NULL) {
8556 XP_ERROR0(XPATH_EXPR_ERROR);
8557 }
8558 }
8559 return(name);
8560}
8561
8562/**
8563 * xmlXPathIsAxisName:
8564 * @name: a preparsed name token
8565 *
8566 * [6] AxisName ::= 'ancestor'
8567 * | 'ancestor-or-self'
8568 * | 'attribute'
8569 * | 'child'
8570 * | 'descendant'
8571 * | 'descendant-or-self'
8572 * | 'following'
8573 * | 'following-sibling'
8574 * | 'namespace'
8575 * | 'parent'
8576 * | 'preceding'
8577 * | 'preceding-sibling'
8578 * | 'self'
8579 *
8580 * Returns the axis or 0
8581 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008582static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008583xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008584 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008585 switch (name[0]) {
8586 case 'a':
8587 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8588 ret = AXIS_ANCESTOR;
8589 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8590 ret = AXIS_ANCESTOR_OR_SELF;
8591 if (xmlStrEqual(name, BAD_CAST "attribute"))
8592 ret = AXIS_ATTRIBUTE;
8593 break;
8594 case 'c':
8595 if (xmlStrEqual(name, BAD_CAST "child"))
8596 ret = AXIS_CHILD;
8597 break;
8598 case 'd':
8599 if (xmlStrEqual(name, BAD_CAST "descendant"))
8600 ret = AXIS_DESCENDANT;
8601 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8602 ret = AXIS_DESCENDANT_OR_SELF;
8603 break;
8604 case 'f':
8605 if (xmlStrEqual(name, BAD_CAST "following"))
8606 ret = AXIS_FOLLOWING;
8607 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8608 ret = AXIS_FOLLOWING_SIBLING;
8609 break;
8610 case 'n':
8611 if (xmlStrEqual(name, BAD_CAST "namespace"))
8612 ret = AXIS_NAMESPACE;
8613 break;
8614 case 'p':
8615 if (xmlStrEqual(name, BAD_CAST "parent"))
8616 ret = AXIS_PARENT;
8617 if (xmlStrEqual(name, BAD_CAST "preceding"))
8618 ret = AXIS_PRECEDING;
8619 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8620 ret = AXIS_PRECEDING_SIBLING;
8621 break;
8622 case 's':
8623 if (xmlStrEqual(name, BAD_CAST "self"))
8624 ret = AXIS_SELF;
8625 break;
8626 }
8627 return(ret);
8628}
8629
8630/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008631 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008632 * @ctxt: the XPath Parser context
8633 *
8634 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8635 * | AbbreviatedStep
8636 *
8637 * [12] AbbreviatedStep ::= '.' | '..'
8638 *
8639 * [5] AxisSpecifier ::= AxisName '::'
8640 * | AbbreviatedAxisSpecifier
8641 *
8642 * [13] AbbreviatedAxisSpecifier ::= '@'?
8643 *
8644 * Modified for XPtr range support as:
8645 *
8646 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8647 * | AbbreviatedStep
8648 * | 'range-to' '(' Expr ')' Predicate*
8649 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008650 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008651 * A location step of . is short for self::node(). This is
8652 * particularly useful in conjunction with //. For example, the
8653 * location path .//para is short for
8654 * self::node()/descendant-or-self::node()/child::para
8655 * and so will select all para descendant elements of the context
8656 * node.
8657 * Similarly, a location step of .. is short for parent::node().
8658 * For example, ../title is short for parent::node()/child::title
8659 * and so will select the title children of the parent of the context
8660 * node.
8661 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008662static void
8663xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008664#ifdef LIBXML_XPTR_ENABLED
8665 int rangeto = 0;
8666 int op2 = -1;
8667#endif
8668
Owen Taylor3473f882001-02-23 17:55:21 +00008669 SKIP_BLANKS;
8670 if ((CUR == '.') && (NXT(1) == '.')) {
8671 SKIP(2);
8672 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008673 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8674 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008675 } else if (CUR == '.') {
8676 NEXT;
8677 SKIP_BLANKS;
8678 } else {
8679 xmlChar *name = NULL;
8680 const xmlChar *prefix = NULL;
8681 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008682 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008683 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008684 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008685
8686 /*
8687 * The modification needed for XPointer change to the production
8688 */
8689#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008690 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008691 name = xmlXPathParseNCName(ctxt);
8692 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008693 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008694 xmlFree(name);
8695 SKIP_BLANKS;
8696 if (CUR != '(') {
8697 XP_ERROR(XPATH_EXPR_ERROR);
8698 }
8699 NEXT;
8700 SKIP_BLANKS;
8701
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008702 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008703 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008704 CHECK_ERROR;
8705
8706 SKIP_BLANKS;
8707 if (CUR != ')') {
8708 XP_ERROR(XPATH_EXPR_ERROR);
8709 }
8710 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008711 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008712 goto eval_predicates;
8713 }
8714 }
8715#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008716 if (CUR == '*') {
8717 axis = AXIS_CHILD;
8718 } else {
8719 if (name == NULL)
8720 name = xmlXPathParseNCName(ctxt);
8721 if (name != NULL) {
8722 axis = xmlXPathIsAxisName(name);
8723 if (axis != 0) {
8724 SKIP_BLANKS;
8725 if ((CUR == ':') && (NXT(1) == ':')) {
8726 SKIP(2);
8727 xmlFree(name);
8728 name = NULL;
8729 } else {
8730 /* an element name can conflict with an axis one :-\ */
8731 axis = AXIS_CHILD;
8732 }
Owen Taylor3473f882001-02-23 17:55:21 +00008733 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008734 axis = AXIS_CHILD;
8735 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008736 } else if (CUR == '@') {
8737 NEXT;
8738 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008739 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008740 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008741 }
Owen Taylor3473f882001-02-23 17:55:21 +00008742 }
8743
8744 CHECK_ERROR;
8745
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008746 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008747 if (test == 0)
8748 return;
8749
8750#ifdef DEBUG_STEP
8751 xmlGenericError(xmlGenericErrorContext,
8752 "Basis : computing new set\n");
8753#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008754
Owen Taylor3473f882001-02-23 17:55:21 +00008755#ifdef DEBUG_STEP
8756 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008757 if (ctxt->value == NULL)
8758 xmlGenericError(xmlGenericErrorContext, "no value\n");
8759 else if (ctxt->value->nodesetval == NULL)
8760 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8761 else
8762 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008763#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008764
8765eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008766 op1 = ctxt->comp->last;
8767 ctxt->comp->last = -1;
8768
Owen Taylor3473f882001-02-23 17:55:21 +00008769 SKIP_BLANKS;
8770 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008771 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008772 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008773
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008774#ifdef LIBXML_XPTR_ENABLED
8775 if (rangeto) {
8776 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8777 } else
8778#endif
8779 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8780 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008781
Owen Taylor3473f882001-02-23 17:55:21 +00008782 }
8783#ifdef DEBUG_STEP
8784 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008785 if (ctxt->value == NULL)
8786 xmlGenericError(xmlGenericErrorContext, "no value\n");
8787 else if (ctxt->value->nodesetval == NULL)
8788 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8789 else
8790 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8791 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008792#endif
8793}
8794
8795/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008796 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008797 * @ctxt: the XPath Parser context
8798 *
8799 * [3] RelativeLocationPath ::= Step
8800 * | RelativeLocationPath '/' Step
8801 * | AbbreviatedRelativeLocationPath
8802 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8803 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008804 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008805 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008806static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008807xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008808(xmlXPathParserContextPtr ctxt) {
8809 SKIP_BLANKS;
8810 if ((CUR == '/') && (NXT(1) == '/')) {
8811 SKIP(2);
8812 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008813 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8814 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008815 } else if (CUR == '/') {
8816 NEXT;
8817 SKIP_BLANKS;
8818 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008819 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008820 SKIP_BLANKS;
8821 while (CUR == '/') {
8822 if ((CUR == '/') && (NXT(1) == '/')) {
8823 SKIP(2);
8824 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008825 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008826 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008827 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008828 } else if (CUR == '/') {
8829 NEXT;
8830 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008831 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008832 }
8833 SKIP_BLANKS;
8834 }
8835}
8836
8837/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008838 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008839 * @ctxt: the XPath Parser context
8840 *
8841 * [1] LocationPath ::= RelativeLocationPath
8842 * | AbsoluteLocationPath
8843 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8844 * | AbbreviatedAbsoluteLocationPath
8845 * [10] AbbreviatedAbsoluteLocationPath ::=
8846 * '//' RelativeLocationPath
8847 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008848 * Compile a location path
8849 *
Owen Taylor3473f882001-02-23 17:55:21 +00008850 * // is short for /descendant-or-self::node()/. For example,
8851 * //para is short for /descendant-or-self::node()/child::para and
8852 * so will select any para element in the document (even a para element
8853 * that is a document element will be selected by //para since the
8854 * document element node is a child of the root node); div//para is
8855 * short for div/descendant-or-self::node()/child::para and so will
8856 * select all para descendants of div children.
8857 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008858static void
8859xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008860 SKIP_BLANKS;
8861 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008862 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008863 } else {
8864 while (CUR == '/') {
8865 if ((CUR == '/') && (NXT(1) == '/')) {
8866 SKIP(2);
8867 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008868 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8869 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008870 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008871 } else if (CUR == '/') {
8872 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008873 SKIP_BLANKS;
8874 if ((CUR != 0 ) &&
William M. Brack76e95df2003-10-18 16:20:14 +00008875 ((IS_LETTER_CH(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00008876 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008877 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008878 }
8879 }
8880 }
8881}
8882
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008883/************************************************************************
8884 * *
8885 * XPath precompiled expression evaluation *
8886 * *
8887 ************************************************************************/
8888
Daniel Veillardf06307e2001-07-03 10:35:50 +00008889static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008890xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8891
8892/**
8893 * xmlXPathNodeCollectAndTest:
8894 * @ctxt: the XPath Parser context
8895 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008896 * @first: pointer to the first element in document order
8897 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008898 *
8899 * This is the function implementing a step: based on the current list
8900 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00008901 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008902 *
8903 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008904 *
William M. Brack08171912003-12-29 02:52:11 +00008905 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008906 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008907static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008908xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008909 xmlXPathStepOpPtr op,
8910 xmlNodePtr * first, xmlNodePtr * last)
8911{
William M. Brack78637da2003-07-31 14:47:38 +00008912 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
8913 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
8914 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008915 const xmlChar *prefix = op->value4;
8916 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008917 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008918
8919#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008920 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008921#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008922 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008923 xmlNodeSetPtr ret, list;
8924 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008925 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00008926 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008927 xmlNodePtr cur = NULL;
8928 xmlXPathObjectPtr obj;
8929 xmlNodeSetPtr nodelist;
8930 xmlNodePtr tmp;
8931
Daniel Veillardf06307e2001-07-03 10:35:50 +00008932 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008933 obj = valuePop(ctxt);
8934 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00008935 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008936 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008937 URI = xmlXPathNsLookup(ctxt->context, prefix);
8938 if (URI == NULL)
8939 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00008940 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008941#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008942 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008943#endif
8944 switch (axis) {
8945 case AXIS_ANCESTOR:
8946#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008947 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008948#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008949 first = NULL;
8950 next = xmlXPathNextAncestor;
8951 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008952 case AXIS_ANCESTOR_OR_SELF:
8953#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008954 xmlGenericError(xmlGenericErrorContext,
8955 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008956#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008957 first = NULL;
8958 next = xmlXPathNextAncestorOrSelf;
8959 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008960 case AXIS_ATTRIBUTE:
8961#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008962 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008963#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008964 first = NULL;
8965 last = NULL;
8966 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00008967 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008968 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008969 case AXIS_CHILD:
8970#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008971 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008972#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008973 last = NULL;
8974 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00008975 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008976 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008977 case AXIS_DESCENDANT:
8978#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008979 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008980#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008981 last = NULL;
8982 next = xmlXPathNextDescendant;
8983 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008984 case AXIS_DESCENDANT_OR_SELF:
8985#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008986 xmlGenericError(xmlGenericErrorContext,
8987 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008988#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008989 last = NULL;
8990 next = xmlXPathNextDescendantOrSelf;
8991 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008992 case AXIS_FOLLOWING:
8993#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00008994 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008995#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00008996 last = NULL;
8997 next = xmlXPathNextFollowing;
8998 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008999 case AXIS_FOLLOWING_SIBLING:
9000#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009001 xmlGenericError(xmlGenericErrorContext,
9002 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009003#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009004 last = NULL;
9005 next = xmlXPathNextFollowingSibling;
9006 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009007 case AXIS_NAMESPACE:
9008#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009009 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009010#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009011 first = NULL;
9012 last = NULL;
9013 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009014 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009015 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009016 case AXIS_PARENT:
9017#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009018 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009019#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009020 first = NULL;
9021 next = xmlXPathNextParent;
9022 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009023 case AXIS_PRECEDING:
9024#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009025 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009026#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009027 first = NULL;
9028 next = xmlXPathNextPrecedingInternal;
9029 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009030 case AXIS_PRECEDING_SIBLING:
9031#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009032 xmlGenericError(xmlGenericErrorContext,
9033 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009034#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009035 first = NULL;
9036 next = xmlXPathNextPrecedingSibling;
9037 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009038 case AXIS_SELF:
9039#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009040 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009041#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009042 first = NULL;
9043 last = NULL;
9044 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009045 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009046 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009047 }
9048 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009049 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009050
9051 nodelist = obj->nodesetval;
9052 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009053 xmlXPathFreeObject(obj);
9054 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9055 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009056 }
9057 addNode = xmlXPathNodeSetAddUnique;
9058 ret = NULL;
9059#ifdef DEBUG_STEP
9060 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009061 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009062 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009063 case NODE_TEST_NONE:
9064 xmlGenericError(xmlGenericErrorContext,
9065 " searching for none !!!\n");
9066 break;
9067 case NODE_TEST_TYPE:
9068 xmlGenericError(xmlGenericErrorContext,
9069 " searching for type %d\n", type);
9070 break;
9071 case NODE_TEST_PI:
9072 xmlGenericError(xmlGenericErrorContext,
9073 " searching for PI !!!\n");
9074 break;
9075 case NODE_TEST_ALL:
9076 xmlGenericError(xmlGenericErrorContext,
9077 " searching for *\n");
9078 break;
9079 case NODE_TEST_NS:
9080 xmlGenericError(xmlGenericErrorContext,
9081 " searching for namespace %s\n",
9082 prefix);
9083 break;
9084 case NODE_TEST_NAME:
9085 xmlGenericError(xmlGenericErrorContext,
9086 " searching for name %s\n", name);
9087 if (prefix != NULL)
9088 xmlGenericError(xmlGenericErrorContext,
9089 " with namespace %s\n", prefix);
9090 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009091 }
9092 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9093#endif
9094 /*
9095 * 2.3 Node Tests
9096 * - For the attribute axis, the principal node type is attribute.
9097 * - For the namespace axis, the principal node type is namespace.
9098 * - For other axes, the principal node type is element.
9099 *
9100 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009101 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009102 * select all element children of the context node
9103 */
9104 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009105 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009106 ctxt->context->node = nodelist->nodeTab[i];
9107
Daniel Veillardf06307e2001-07-03 10:35:50 +00009108 cur = NULL;
9109 list = xmlXPathNodeSetCreate(NULL);
9110 do {
9111 cur = next(ctxt, cur);
9112 if (cur == NULL)
9113 break;
9114 if ((first != NULL) && (*first == cur))
9115 break;
9116 if (((t % 256) == 0) &&
9117 (first != NULL) && (*first != NULL) &&
9118 (xmlXPathCmpNodes(*first, cur) >= 0))
9119 break;
9120 if ((last != NULL) && (*last == cur))
9121 break;
9122 if (((t % 256) == 0) &&
9123 (last != NULL) && (*last != NULL) &&
9124 (xmlXPathCmpNodes(cur, *last) >= 0))
9125 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009126 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009127#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009128 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9129#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009130 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009131 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009132 ctxt->context->node = tmp;
9133 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009134 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009135 if ((cur->type == type) ||
9136 ((type == NODE_TYPE_NODE) &&
9137 ((cur->type == XML_DOCUMENT_NODE) ||
9138 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9139 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009140 (cur->type == XML_NAMESPACE_DECL) ||
9141 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009142 (cur->type == XML_PI_NODE) ||
9143 (cur->type == XML_COMMENT_NODE) ||
9144 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009145 (cur->type == XML_TEXT_NODE))) ||
9146 ((type == NODE_TYPE_TEXT) &&
9147 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009148#ifdef DEBUG_STEP
9149 n++;
9150#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009151 addNode(list, cur);
9152 }
9153 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009154 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009155 if (cur->type == XML_PI_NODE) {
9156 if ((name != NULL) &&
9157 (!xmlStrEqual(name, cur->name)))
9158 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009159#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009160 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009161#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009162 addNode(list, cur);
9163 }
9164 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009165 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009166 if (axis == AXIS_ATTRIBUTE) {
9167 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009168#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009169 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009170#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009171 addNode(list, cur);
9172 }
9173 } else if (axis == AXIS_NAMESPACE) {
9174 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009175#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009176 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009177#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009178 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9179 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009180 }
9181 } else {
9182 if (cur->type == XML_ELEMENT_NODE) {
9183 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009184#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009185 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009186#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009187 addNode(list, cur);
9188 } else if ((cur->ns != NULL) &&
9189 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009190#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009191 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009192#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009193 addNode(list, cur);
9194 }
9195 }
9196 }
9197 break;
9198 case NODE_TEST_NS:{
9199 TODO;
9200 break;
9201 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009202 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009203 switch (cur->type) {
9204 case XML_ELEMENT_NODE:
9205 if (xmlStrEqual(name, cur->name)) {
9206 if (prefix == NULL) {
9207 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009208#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009209 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009210#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009211 addNode(list, cur);
9212 }
9213 } else {
9214 if ((cur->ns != NULL) &&
9215 (xmlStrEqual(URI,
9216 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009217#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009218 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009219#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009220 addNode(list, cur);
9221 }
9222 }
9223 }
9224 break;
9225 case XML_ATTRIBUTE_NODE:{
9226 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009227
Daniel Veillardf06307e2001-07-03 10:35:50 +00009228 if (xmlStrEqual(name, attr->name)) {
9229 if (prefix == NULL) {
9230 if ((attr->ns == NULL) ||
9231 (attr->ns->prefix == NULL)) {
9232#ifdef DEBUG_STEP
9233 n++;
9234#endif
9235 addNode(list,
9236 (xmlNodePtr) attr);
9237 }
9238 } else {
9239 if ((attr->ns != NULL) &&
9240 (xmlStrEqual(URI,
9241 attr->ns->
9242 href))) {
9243#ifdef DEBUG_STEP
9244 n++;
9245#endif
9246 addNode(list,
9247 (xmlNodePtr) attr);
9248 }
9249 }
9250 }
9251 break;
9252 }
9253 case XML_NAMESPACE_DECL:
9254 if (cur->type == XML_NAMESPACE_DECL) {
9255 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009256
Daniel Veillardf06307e2001-07-03 10:35:50 +00009257 if ((ns->prefix != NULL) && (name != NULL)
9258 && (xmlStrEqual(ns->prefix, name))) {
9259#ifdef DEBUG_STEP
9260 n++;
9261#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009262 xmlXPathNodeSetAddNs(list,
9263 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009264 }
9265 }
9266 break;
9267 default:
9268 break;
9269 }
9270 break;
9271 break;
9272 }
9273 } while (cur != NULL);
9274
9275 /*
9276 * If there is some predicate filtering do it now
9277 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009278 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009279 xmlXPathObjectPtr obj2;
9280
9281 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9282 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9283 CHECK_TYPE0(XPATH_NODESET);
9284 obj2 = valuePop(ctxt);
9285 list = obj2->nodesetval;
9286 obj2->nodesetval = NULL;
9287 xmlXPathFreeObject(obj2);
9288 }
9289 if (ret == NULL) {
9290 ret = list;
9291 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009292 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009293 xmlXPathFreeNodeSet(list);
9294 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009295 }
9296 ctxt->context->node = tmp;
9297#ifdef DEBUG_STEP
9298 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009299 "\nExamined %d nodes, found %d nodes at that step\n",
9300 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009301#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009302 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009303 if ((obj->boolval) && (obj->user != NULL)) {
9304 ctxt->value->boolval = 1;
9305 ctxt->value->user = obj->user;
9306 obj->user = NULL;
9307 obj->boolval = 0;
9308 }
9309 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009310 return(t);
9311}
9312
9313/**
9314 * xmlXPathNodeCollectAndTestNth:
9315 * @ctxt: the XPath Parser context
9316 * @op: the XPath precompiled step operation
9317 * @indx: the index to collect
9318 * @first: pointer to the first element in document order
9319 * @last: pointer to the last element in document order
9320 *
9321 * This is the function implementing a step: based on the current list
9322 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009323 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009324 *
9325 * Pushes the new NodeSet resulting from the search.
9326 * Returns the number of node traversed
9327 */
9328static int
9329xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9330 xmlXPathStepOpPtr op, int indx,
9331 xmlNodePtr * first, xmlNodePtr * last)
9332{
William M. Brack78637da2003-07-31 14:47:38 +00009333 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9334 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9335 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009336 const xmlChar *prefix = op->value4;
9337 const xmlChar *name = op->value5;
9338 const xmlChar *URI = NULL;
9339 int n = 0, t = 0;
9340
9341 int i;
9342 xmlNodeSetPtr list;
9343 xmlXPathTraversalFunction next = NULL;
9344 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9345 xmlNodePtr cur = NULL;
9346 xmlXPathObjectPtr obj;
9347 xmlNodeSetPtr nodelist;
9348 xmlNodePtr tmp;
9349
9350 CHECK_TYPE0(XPATH_NODESET);
9351 obj = valuePop(ctxt);
9352 addNode = xmlXPathNodeSetAdd;
9353 if (prefix != NULL) {
9354 URI = xmlXPathNsLookup(ctxt->context, prefix);
9355 if (URI == NULL)
9356 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9357 }
9358#ifdef DEBUG_STEP_NTH
9359 xmlGenericError(xmlGenericErrorContext, "new step : ");
9360 if (first != NULL) {
9361 if (*first != NULL)
9362 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9363 (*first)->name);
9364 else
9365 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9366 }
9367 if (last != NULL) {
9368 if (*last != NULL)
9369 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9370 (*last)->name);
9371 else
9372 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9373 }
9374#endif
9375 switch (axis) {
9376 case AXIS_ANCESTOR:
9377#ifdef DEBUG_STEP_NTH
9378 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9379#endif
9380 first = NULL;
9381 next = xmlXPathNextAncestor;
9382 break;
9383 case AXIS_ANCESTOR_OR_SELF:
9384#ifdef DEBUG_STEP_NTH
9385 xmlGenericError(xmlGenericErrorContext,
9386 "axis 'ancestors-or-self' ");
9387#endif
9388 first = NULL;
9389 next = xmlXPathNextAncestorOrSelf;
9390 break;
9391 case AXIS_ATTRIBUTE:
9392#ifdef DEBUG_STEP_NTH
9393 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9394#endif
9395 first = NULL;
9396 last = NULL;
9397 next = xmlXPathNextAttribute;
9398 break;
9399 case AXIS_CHILD:
9400#ifdef DEBUG_STEP_NTH
9401 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9402#endif
9403 last = NULL;
9404 next = xmlXPathNextChild;
9405 break;
9406 case AXIS_DESCENDANT:
9407#ifdef DEBUG_STEP_NTH
9408 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9409#endif
9410 last = NULL;
9411 next = xmlXPathNextDescendant;
9412 break;
9413 case AXIS_DESCENDANT_OR_SELF:
9414#ifdef DEBUG_STEP_NTH
9415 xmlGenericError(xmlGenericErrorContext,
9416 "axis 'descendant-or-self' ");
9417#endif
9418 last = NULL;
9419 next = xmlXPathNextDescendantOrSelf;
9420 break;
9421 case AXIS_FOLLOWING:
9422#ifdef DEBUG_STEP_NTH
9423 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9424#endif
9425 last = NULL;
9426 next = xmlXPathNextFollowing;
9427 break;
9428 case AXIS_FOLLOWING_SIBLING:
9429#ifdef DEBUG_STEP_NTH
9430 xmlGenericError(xmlGenericErrorContext,
9431 "axis 'following-siblings' ");
9432#endif
9433 last = NULL;
9434 next = xmlXPathNextFollowingSibling;
9435 break;
9436 case AXIS_NAMESPACE:
9437#ifdef DEBUG_STEP_NTH
9438 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9439#endif
9440 last = NULL;
9441 first = NULL;
9442 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9443 break;
9444 case AXIS_PARENT:
9445#ifdef DEBUG_STEP_NTH
9446 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9447#endif
9448 first = NULL;
9449 next = xmlXPathNextParent;
9450 break;
9451 case AXIS_PRECEDING:
9452#ifdef DEBUG_STEP_NTH
9453 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9454#endif
9455 first = NULL;
9456 next = xmlXPathNextPrecedingInternal;
9457 break;
9458 case AXIS_PRECEDING_SIBLING:
9459#ifdef DEBUG_STEP_NTH
9460 xmlGenericError(xmlGenericErrorContext,
9461 "axis 'preceding-sibling' ");
9462#endif
9463 first = NULL;
9464 next = xmlXPathNextPrecedingSibling;
9465 break;
9466 case AXIS_SELF:
9467#ifdef DEBUG_STEP_NTH
9468 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9469#endif
9470 first = NULL;
9471 last = NULL;
9472 next = xmlXPathNextSelf;
9473 break;
9474 }
9475 if (next == NULL)
9476 return(0);
9477
9478 nodelist = obj->nodesetval;
9479 if (nodelist == NULL) {
9480 xmlXPathFreeObject(obj);
9481 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9482 return(0);
9483 }
9484 addNode = xmlXPathNodeSetAddUnique;
9485#ifdef DEBUG_STEP_NTH
9486 xmlGenericError(xmlGenericErrorContext,
9487 " context contains %d nodes\n", nodelist->nodeNr);
9488 switch (test) {
9489 case NODE_TEST_NONE:
9490 xmlGenericError(xmlGenericErrorContext,
9491 " searching for none !!!\n");
9492 break;
9493 case NODE_TEST_TYPE:
9494 xmlGenericError(xmlGenericErrorContext,
9495 " searching for type %d\n", type);
9496 break;
9497 case NODE_TEST_PI:
9498 xmlGenericError(xmlGenericErrorContext,
9499 " searching for PI !!!\n");
9500 break;
9501 case NODE_TEST_ALL:
9502 xmlGenericError(xmlGenericErrorContext,
9503 " searching for *\n");
9504 break;
9505 case NODE_TEST_NS:
9506 xmlGenericError(xmlGenericErrorContext,
9507 " searching for namespace %s\n",
9508 prefix);
9509 break;
9510 case NODE_TEST_NAME:
9511 xmlGenericError(xmlGenericErrorContext,
9512 " searching for name %s\n", name);
9513 if (prefix != NULL)
9514 xmlGenericError(xmlGenericErrorContext,
9515 " with namespace %s\n", prefix);
9516 break;
9517 }
9518 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9519#endif
9520 /*
9521 * 2.3 Node Tests
9522 * - For the attribute axis, the principal node type is attribute.
9523 * - For the namespace axis, the principal node type is namespace.
9524 * - For other axes, the principal node type is element.
9525 *
9526 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009527 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009528 * select all element children of the context node
9529 */
9530 tmp = ctxt->context->node;
9531 list = xmlXPathNodeSetCreate(NULL);
9532 for (i = 0; i < nodelist->nodeNr; i++) {
9533 ctxt->context->node = nodelist->nodeTab[i];
9534
9535 cur = NULL;
9536 n = 0;
9537 do {
9538 cur = next(ctxt, cur);
9539 if (cur == NULL)
9540 break;
9541 if ((first != NULL) && (*first == cur))
9542 break;
9543 if (((t % 256) == 0) &&
9544 (first != NULL) && (*first != NULL) &&
9545 (xmlXPathCmpNodes(*first, cur) >= 0))
9546 break;
9547 if ((last != NULL) && (*last == cur))
9548 break;
9549 if (((t % 256) == 0) &&
9550 (last != NULL) && (*last != NULL) &&
9551 (xmlXPathCmpNodes(cur, *last) >= 0))
9552 break;
9553 t++;
9554 switch (test) {
9555 case NODE_TEST_NONE:
9556 ctxt->context->node = tmp;
9557 STRANGE return(0);
9558 case NODE_TEST_TYPE:
9559 if ((cur->type == type) ||
9560 ((type == NODE_TYPE_NODE) &&
9561 ((cur->type == XML_DOCUMENT_NODE) ||
9562 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9563 (cur->type == XML_ELEMENT_NODE) ||
9564 (cur->type == XML_PI_NODE) ||
9565 (cur->type == XML_COMMENT_NODE) ||
9566 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009567 (cur->type == XML_TEXT_NODE))) ||
9568 ((type == NODE_TYPE_TEXT) &&
9569 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009570 n++;
9571 if (n == indx)
9572 addNode(list, cur);
9573 }
9574 break;
9575 case NODE_TEST_PI:
9576 if (cur->type == XML_PI_NODE) {
9577 if ((name != NULL) &&
9578 (!xmlStrEqual(name, cur->name)))
9579 break;
9580 n++;
9581 if (n == indx)
9582 addNode(list, cur);
9583 }
9584 break;
9585 case NODE_TEST_ALL:
9586 if (axis == AXIS_ATTRIBUTE) {
9587 if (cur->type == XML_ATTRIBUTE_NODE) {
9588 n++;
9589 if (n == indx)
9590 addNode(list, cur);
9591 }
9592 } else if (axis == AXIS_NAMESPACE) {
9593 if (cur->type == XML_NAMESPACE_DECL) {
9594 n++;
9595 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009596 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9597 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009598 }
9599 } else {
9600 if (cur->type == XML_ELEMENT_NODE) {
9601 if (prefix == NULL) {
9602 n++;
9603 if (n == indx)
9604 addNode(list, cur);
9605 } else if ((cur->ns != NULL) &&
9606 (xmlStrEqual(URI, cur->ns->href))) {
9607 n++;
9608 if (n == indx)
9609 addNode(list, cur);
9610 }
9611 }
9612 }
9613 break;
9614 case NODE_TEST_NS:{
9615 TODO;
9616 break;
9617 }
9618 case NODE_TEST_NAME:
9619 switch (cur->type) {
9620 case XML_ELEMENT_NODE:
9621 if (xmlStrEqual(name, cur->name)) {
9622 if (prefix == NULL) {
9623 if (cur->ns == NULL) {
9624 n++;
9625 if (n == indx)
9626 addNode(list, cur);
9627 }
9628 } else {
9629 if ((cur->ns != NULL) &&
9630 (xmlStrEqual(URI,
9631 cur->ns->href))) {
9632 n++;
9633 if (n == indx)
9634 addNode(list, cur);
9635 }
9636 }
9637 }
9638 break;
9639 case XML_ATTRIBUTE_NODE:{
9640 xmlAttrPtr attr = (xmlAttrPtr) cur;
9641
9642 if (xmlStrEqual(name, attr->name)) {
9643 if (prefix == NULL) {
9644 if ((attr->ns == NULL) ||
9645 (attr->ns->prefix == NULL)) {
9646 n++;
9647 if (n == indx)
9648 addNode(list, cur);
9649 }
9650 } else {
9651 if ((attr->ns != NULL) &&
9652 (xmlStrEqual(URI,
9653 attr->ns->
9654 href))) {
9655 n++;
9656 if (n == indx)
9657 addNode(list, cur);
9658 }
9659 }
9660 }
9661 break;
9662 }
9663 case XML_NAMESPACE_DECL:
9664 if (cur->type == XML_NAMESPACE_DECL) {
9665 xmlNsPtr ns = (xmlNsPtr) cur;
9666
9667 if ((ns->prefix != NULL) && (name != NULL)
9668 && (xmlStrEqual(ns->prefix, name))) {
9669 n++;
9670 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009671 xmlXPathNodeSetAddNs(list,
9672 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009673 }
9674 }
9675 break;
9676 default:
9677 break;
9678 }
9679 break;
9680 break;
9681 }
9682 } while (n < indx);
9683 }
9684 ctxt->context->node = tmp;
9685#ifdef DEBUG_STEP_NTH
9686 xmlGenericError(xmlGenericErrorContext,
9687 "\nExamined %d nodes, found %d nodes at that step\n",
9688 t, list->nodeNr);
9689#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009690 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009691 if ((obj->boolval) && (obj->user != NULL)) {
9692 ctxt->value->boolval = 1;
9693 ctxt->value->user = obj->user;
9694 obj->user = NULL;
9695 obj->boolval = 0;
9696 }
9697 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009698 return(t);
9699}
9700
9701/**
9702 * xmlXPathCompOpEvalFirst:
9703 * @ctxt: the XPath parser context with the compiled expression
9704 * @op: an XPath compiled operation
9705 * @first: the first elem found so far
9706 *
9707 * Evaluate the Precompiled XPath operation searching only the first
9708 * element in document order
9709 *
9710 * Returns the number of examined objects.
9711 */
9712static int
9713xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9714 xmlXPathStepOpPtr op, xmlNodePtr * first)
9715{
9716 int total = 0, cur;
9717 xmlXPathCompExprPtr comp;
9718 xmlXPathObjectPtr arg1, arg2;
9719
Daniel Veillard556c6682001-10-06 09:59:51 +00009720 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009721 comp = ctxt->comp;
9722 switch (op->op) {
9723 case XPATH_OP_END:
9724 return (0);
9725 case XPATH_OP_UNION:
9726 total =
9727 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9728 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009729 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009730 if ((ctxt->value != NULL)
9731 && (ctxt->value->type == XPATH_NODESET)
9732 && (ctxt->value->nodesetval != NULL)
9733 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9734 /*
9735 * limit tree traversing to first node in the result
9736 */
9737 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9738 *first = ctxt->value->nodesetval->nodeTab[0];
9739 }
9740 cur =
9741 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9742 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009743 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009744 CHECK_TYPE0(XPATH_NODESET);
9745 arg2 = valuePop(ctxt);
9746
9747 CHECK_TYPE0(XPATH_NODESET);
9748 arg1 = valuePop(ctxt);
9749
9750 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9751 arg2->nodesetval);
9752 valuePush(ctxt, arg1);
9753 xmlXPathFreeObject(arg2);
9754 /* optimizer */
9755 if (total > cur)
9756 xmlXPathCompSwap(op);
9757 return (total + cur);
9758 case XPATH_OP_ROOT:
9759 xmlXPathRoot(ctxt);
9760 return (0);
9761 case XPATH_OP_NODE:
9762 if (op->ch1 != -1)
9763 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009764 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009765 if (op->ch2 != -1)
9766 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009767 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009768 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9769 return (total);
9770 case XPATH_OP_RESET:
9771 if (op->ch1 != -1)
9772 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009773 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009774 if (op->ch2 != -1)
9775 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009776 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009777 ctxt->context->node = NULL;
9778 return (total);
9779 case XPATH_OP_COLLECT:{
9780 if (op->ch1 == -1)
9781 return (total);
9782
9783 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009784 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009785
9786 /*
9787 * Optimization for [n] selection where n is a number
9788 */
9789 if ((op->ch2 != -1) &&
9790 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9791 (comp->steps[op->ch2].ch1 == -1) &&
9792 (comp->steps[op->ch2].ch2 != -1) &&
9793 (comp->steps[comp->steps[op->ch2].ch2].op ==
9794 XPATH_OP_VALUE)) {
9795 xmlXPathObjectPtr val;
9796
9797 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9798 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9799 int indx = (int) val->floatval;
9800
9801 if (val->floatval == (float) indx) {
9802 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9803 first, NULL);
9804 return (total);
9805 }
9806 }
9807 }
9808 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9809 return (total);
9810 }
9811 case XPATH_OP_VALUE:
9812 valuePush(ctxt,
9813 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9814 return (0);
9815 case XPATH_OP_SORT:
9816 if (op->ch1 != -1)
9817 total +=
9818 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9819 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009820 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009821 if ((ctxt->value != NULL)
9822 && (ctxt->value->type == XPATH_NODESET)
9823 && (ctxt->value->nodesetval != NULL))
9824 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9825 return (total);
9826 default:
9827 return (xmlXPathCompOpEval(ctxt, op));
9828 }
9829}
9830
9831/**
9832 * xmlXPathCompOpEvalLast:
9833 * @ctxt: the XPath parser context with the compiled expression
9834 * @op: an XPath compiled operation
9835 * @last: the last elem found so far
9836 *
9837 * Evaluate the Precompiled XPath operation searching only the last
9838 * element in document order
9839 *
William M. Brack08171912003-12-29 02:52:11 +00009840 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +00009841 */
9842static int
9843xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9844 xmlNodePtr * last)
9845{
9846 int total = 0, cur;
9847 xmlXPathCompExprPtr comp;
9848 xmlXPathObjectPtr arg1, arg2;
9849
Daniel Veillard556c6682001-10-06 09:59:51 +00009850 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009851 comp = ctxt->comp;
9852 switch (op->op) {
9853 case XPATH_OP_END:
9854 return (0);
9855 case XPATH_OP_UNION:
9856 total =
9857 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009858 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009859 if ((ctxt->value != NULL)
9860 && (ctxt->value->type == XPATH_NODESET)
9861 && (ctxt->value->nodesetval != NULL)
9862 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9863 /*
9864 * limit tree traversing to first node in the result
9865 */
9866 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9867 *last =
9868 ctxt->value->nodesetval->nodeTab[ctxt->value->
9869 nodesetval->nodeNr -
9870 1];
9871 }
9872 cur =
9873 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009874 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009875 if ((ctxt->value != NULL)
9876 && (ctxt->value->type == XPATH_NODESET)
9877 && (ctxt->value->nodesetval != NULL)
9878 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9879 }
9880 CHECK_TYPE0(XPATH_NODESET);
9881 arg2 = valuePop(ctxt);
9882
9883 CHECK_TYPE0(XPATH_NODESET);
9884 arg1 = valuePop(ctxt);
9885
9886 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9887 arg2->nodesetval);
9888 valuePush(ctxt, arg1);
9889 xmlXPathFreeObject(arg2);
9890 /* optimizer */
9891 if (total > cur)
9892 xmlXPathCompSwap(op);
9893 return (total + cur);
9894 case XPATH_OP_ROOT:
9895 xmlXPathRoot(ctxt);
9896 return (0);
9897 case XPATH_OP_NODE:
9898 if (op->ch1 != -1)
9899 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009900 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009901 if (op->ch2 != -1)
9902 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009903 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009904 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9905 return (total);
9906 case XPATH_OP_RESET:
9907 if (op->ch1 != -1)
9908 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009909 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009910 if (op->ch2 != -1)
9911 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009912 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009913 ctxt->context->node = NULL;
9914 return (total);
9915 case XPATH_OP_COLLECT:{
9916 if (op->ch1 == -1)
9917 return (0);
9918
9919 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009920 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009921
9922 /*
9923 * Optimization for [n] selection where n is a number
9924 */
9925 if ((op->ch2 != -1) &&
9926 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9927 (comp->steps[op->ch2].ch1 == -1) &&
9928 (comp->steps[op->ch2].ch2 != -1) &&
9929 (comp->steps[comp->steps[op->ch2].ch2].op ==
9930 XPATH_OP_VALUE)) {
9931 xmlXPathObjectPtr val;
9932
9933 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9934 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9935 int indx = (int) val->floatval;
9936
9937 if (val->floatval == (float) indx) {
9938 total +=
9939 xmlXPathNodeCollectAndTestNth(ctxt, op,
9940 indx, NULL,
9941 last);
9942 return (total);
9943 }
9944 }
9945 }
9946 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9947 return (total);
9948 }
9949 case XPATH_OP_VALUE:
9950 valuePush(ctxt,
9951 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9952 return (0);
9953 case XPATH_OP_SORT:
9954 if (op->ch1 != -1)
9955 total +=
9956 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9957 last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009958 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009959 if ((ctxt->value != NULL)
9960 && (ctxt->value->type == XPATH_NODESET)
9961 && (ctxt->value->nodesetval != NULL))
9962 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9963 return (total);
9964 default:
9965 return (xmlXPathCompOpEval(ctxt, op));
9966 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009967}
9968
Owen Taylor3473f882001-02-23 17:55:21 +00009969/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009970 * xmlXPathCompOpEval:
9971 * @ctxt: the XPath parser context with the compiled expression
9972 * @op: an XPath compiled operation
9973 *
9974 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +00009975 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009976 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009977static int
9978xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9979{
9980 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009981 int equal, ret;
9982 xmlXPathCompExprPtr comp;
9983 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009984 xmlNodePtr bak;
9985 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +00009986 int pp;
William M. Brack692092b2002-06-28 15:01:24 +00009987 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009988
Daniel Veillard556c6682001-10-06 09:59:51 +00009989 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009990 comp = ctxt->comp;
9991 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009992 case XPATH_OP_END:
9993 return (0);
9994 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +00009995 bakd = ctxt->context->doc;
9996 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +00009997 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +00009998 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009999 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010000 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010001 xmlXPathBooleanFunction(ctxt, 1);
10002 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10003 return (total);
10004 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010005 ctxt->context->doc = bakd;
10006 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010007 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010008 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010009 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010010 if (ctxt->error) {
10011 xmlXPathFreeObject(arg2);
10012 return(0);
10013 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010014 xmlXPathBooleanFunction(ctxt, 1);
10015 arg1 = valuePop(ctxt);
10016 arg1->boolval &= arg2->boolval;
10017 valuePush(ctxt, arg1);
10018 xmlXPathFreeObject(arg2);
10019 return (total);
10020 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010021 bakd = ctxt->context->doc;
10022 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010023 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010024 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010025 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010026 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010027 xmlXPathBooleanFunction(ctxt, 1);
10028 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10029 return (total);
10030 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010031 ctxt->context->doc = bakd;
10032 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010033 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010034 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010035 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010036 if (ctxt->error) {
10037 xmlXPathFreeObject(arg2);
10038 return(0);
10039 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010040 xmlXPathBooleanFunction(ctxt, 1);
10041 arg1 = valuePop(ctxt);
10042 arg1->boolval |= arg2->boolval;
10043 valuePush(ctxt, arg1);
10044 xmlXPathFreeObject(arg2);
10045 return (total);
10046 case XPATH_OP_EQUAL:
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 ctxt->context->doc = bakd;
10054 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010055 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010056 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010057 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010058 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010059 if (op->value)
10060 equal = xmlXPathEqualValues(ctxt);
10061 else
10062 equal = xmlXPathNotEqualValues(ctxt);
10063 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010064 return (total);
10065 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010066 bakd = ctxt->context->doc;
10067 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010068 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010069 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010070 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010071 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010072 ctxt->context->doc = bakd;
10073 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010074 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010075 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010076 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010077 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010078 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10079 valuePush(ctxt, xmlXPathNewBoolean(ret));
10080 return (total);
10081 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010082 bakd = ctxt->context->doc;
10083 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010084 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010085 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010086 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010087 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010088 if (op->ch2 != -1) {
10089 ctxt->context->doc = bakd;
10090 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010091 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010092 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010093 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010094 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010095 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010096 if (op->value == 0)
10097 xmlXPathSubValues(ctxt);
10098 else if (op->value == 1)
10099 xmlXPathAddValues(ctxt);
10100 else if (op->value == 2)
10101 xmlXPathValueFlipSign(ctxt);
10102 else if (op->value == 3) {
10103 CAST_TO_NUMBER;
10104 CHECK_TYPE0(XPATH_NUMBER);
10105 }
10106 return (total);
10107 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010108 bakd = ctxt->context->doc;
10109 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010110 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010111 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010112 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010113 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010114 ctxt->context->doc = bakd;
10115 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010116 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010117 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010118 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010119 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010120 if (op->value == 0)
10121 xmlXPathMultValues(ctxt);
10122 else if (op->value == 1)
10123 xmlXPathDivValues(ctxt);
10124 else if (op->value == 2)
10125 xmlXPathModValues(ctxt);
10126 return (total);
10127 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010128 bakd = ctxt->context->doc;
10129 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010130 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010131 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010132 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010133 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010134 ctxt->context->doc = bakd;
10135 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010136 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010137 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010138 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010139 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010140 CHECK_TYPE0(XPATH_NODESET);
10141 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010142
Daniel Veillardf06307e2001-07-03 10:35:50 +000010143 CHECK_TYPE0(XPATH_NODESET);
10144 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010145
Daniel Veillardf06307e2001-07-03 10:35:50 +000010146 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10147 arg2->nodesetval);
10148 valuePush(ctxt, arg1);
10149 xmlXPathFreeObject(arg2);
10150 return (total);
10151 case XPATH_OP_ROOT:
10152 xmlXPathRoot(ctxt);
10153 return (total);
10154 case XPATH_OP_NODE:
10155 if (op->ch1 != -1)
10156 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010157 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010158 if (op->ch2 != -1)
10159 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010160 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010161 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10162 return (total);
10163 case XPATH_OP_RESET:
10164 if (op->ch1 != -1)
10165 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010166 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010167 if (op->ch2 != -1)
10168 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010169 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010170 ctxt->context->node = NULL;
10171 return (total);
10172 case XPATH_OP_COLLECT:{
10173 if (op->ch1 == -1)
10174 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010175
Daniel Veillardf06307e2001-07-03 10:35:50 +000010176 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010177 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010178
Daniel Veillardf06307e2001-07-03 10:35:50 +000010179 /*
10180 * Optimization for [n] selection where n is a number
10181 */
10182 if ((op->ch2 != -1) &&
10183 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10184 (comp->steps[op->ch2].ch1 == -1) &&
10185 (comp->steps[op->ch2].ch2 != -1) &&
10186 (comp->steps[comp->steps[op->ch2].ch2].op ==
10187 XPATH_OP_VALUE)) {
10188 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010189
Daniel Veillardf06307e2001-07-03 10:35:50 +000010190 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10191 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10192 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010193
Daniel Veillardf06307e2001-07-03 10:35:50 +000010194 if (val->floatval == (float) indx) {
10195 total +=
10196 xmlXPathNodeCollectAndTestNth(ctxt, op,
10197 indx, NULL,
10198 NULL);
10199 return (total);
10200 }
10201 }
10202 }
10203 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10204 return (total);
10205 }
10206 case XPATH_OP_VALUE:
10207 valuePush(ctxt,
10208 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10209 return (total);
10210 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010211 xmlXPathObjectPtr val;
10212
Daniel Veillardf06307e2001-07-03 10:35:50 +000010213 if (op->ch1 != -1)
10214 total +=
10215 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010216 if (op->value5 == NULL) {
10217 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10218 if (val == NULL) {
10219 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10220 return(0);
10221 }
10222 valuePush(ctxt, val);
10223 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010224 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010225
Daniel Veillardf06307e2001-07-03 10:35:50 +000010226 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10227 if (URI == NULL) {
10228 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010229 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010230 op->value4, op->value5);
10231 return (total);
10232 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010233 val = xmlXPathVariableLookupNS(ctxt->context,
10234 op->value4, URI);
10235 if (val == NULL) {
10236 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10237 return(0);
10238 }
10239 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010240 }
10241 return (total);
10242 }
10243 case XPATH_OP_FUNCTION:{
10244 xmlXPathFunction func;
10245 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010246 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010247
10248 if (op->ch1 != -1)
10249 total +=
10250 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010251 if (ctxt->valueNr < op->value) {
10252 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010253 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010254 ctxt->error = XPATH_INVALID_OPERAND;
10255 return (total);
10256 }
10257 for (i = 0; i < op->value; i++)
10258 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10259 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010260 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010261 ctxt->error = XPATH_INVALID_OPERAND;
10262 return (total);
10263 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010264 if (op->cache != NULL)
10265 func = (xmlXPathFunction) op->cache;
10266 else {
10267 const xmlChar *URI = NULL;
10268
10269 if (op->value5 == NULL)
10270 func =
10271 xmlXPathFunctionLookup(ctxt->context,
10272 op->value4);
10273 else {
10274 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10275 if (URI == NULL) {
10276 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010277 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010278 op->value4, op->value5);
10279 return (total);
10280 }
10281 func = xmlXPathFunctionLookupNS(ctxt->context,
10282 op->value4, URI);
10283 }
10284 if (func == NULL) {
10285 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010286 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010287 op->value4);
10288 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010289 }
10290 op->cache = (void *) func;
10291 op->cacheURI = (void *) URI;
10292 }
10293 oldFunc = ctxt->context->function;
10294 oldFuncURI = ctxt->context->functionURI;
10295 ctxt->context->function = op->value4;
10296 ctxt->context->functionURI = op->cacheURI;
10297 func(ctxt, op->value);
10298 ctxt->context->function = oldFunc;
10299 ctxt->context->functionURI = oldFuncURI;
10300 return (total);
10301 }
10302 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010303 bakd = ctxt->context->doc;
10304 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010305 if (op->ch1 != -1)
10306 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010307 ctxt->context->doc = bakd;
10308 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010309 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010310 if (op->ch2 != -1)
10311 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010312 ctxt->context->doc = bakd;
10313 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010314 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010315 return (total);
10316 case XPATH_OP_PREDICATE:
10317 case XPATH_OP_FILTER:{
10318 xmlXPathObjectPtr res;
10319 xmlXPathObjectPtr obj, tmp;
10320 xmlNodeSetPtr newset = NULL;
10321 xmlNodeSetPtr oldset;
10322 xmlNodePtr oldnode;
10323 int i;
10324
10325 /*
10326 * Optimization for ()[1] selection i.e. the first elem
10327 */
10328 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10329 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10330 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10331 xmlXPathObjectPtr val;
10332
10333 val = comp->steps[op->ch2].value4;
10334 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10335 (val->floatval == 1.0)) {
10336 xmlNodePtr first = NULL;
10337
10338 total +=
10339 xmlXPathCompOpEvalFirst(ctxt,
10340 &comp->steps[op->ch1],
10341 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010342 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010343 /*
10344 * The nodeset should be in document order,
10345 * Keep only the first value
10346 */
10347 if ((ctxt->value != NULL) &&
10348 (ctxt->value->type == XPATH_NODESET) &&
10349 (ctxt->value->nodesetval != NULL) &&
10350 (ctxt->value->nodesetval->nodeNr > 1))
10351 ctxt->value->nodesetval->nodeNr = 1;
10352 return (total);
10353 }
10354 }
10355 /*
10356 * Optimization for ()[last()] selection i.e. the last elem
10357 */
10358 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10359 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10360 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10361 int f = comp->steps[op->ch2].ch1;
10362
10363 if ((f != -1) &&
10364 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10365 (comp->steps[f].value5 == NULL) &&
10366 (comp->steps[f].value == 0) &&
10367 (comp->steps[f].value4 != NULL) &&
10368 (xmlStrEqual
10369 (comp->steps[f].value4, BAD_CAST "last"))) {
10370 xmlNodePtr last = NULL;
10371
10372 total +=
10373 xmlXPathCompOpEvalLast(ctxt,
10374 &comp->steps[op->ch1],
10375 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010376 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010377 /*
10378 * The nodeset should be in document order,
10379 * Keep only the last value
10380 */
10381 if ((ctxt->value != NULL) &&
10382 (ctxt->value->type == XPATH_NODESET) &&
10383 (ctxt->value->nodesetval != NULL) &&
10384 (ctxt->value->nodesetval->nodeTab != NULL) &&
10385 (ctxt->value->nodesetval->nodeNr > 1)) {
10386 ctxt->value->nodesetval->nodeTab[0] =
10387 ctxt->value->nodesetval->nodeTab[ctxt->
10388 value->
10389 nodesetval->
10390 nodeNr -
10391 1];
10392 ctxt->value->nodesetval->nodeNr = 1;
10393 }
10394 return (total);
10395 }
10396 }
10397
10398 if (op->ch1 != -1)
10399 total +=
10400 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010401 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010402 if (op->ch2 == -1)
10403 return (total);
10404 if (ctxt->value == NULL)
10405 return (total);
10406
10407 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010408
10409#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010410 /*
10411 * Hum are we filtering the result of an XPointer expression
10412 */
10413 if (ctxt->value->type == XPATH_LOCATIONSET) {
10414 xmlLocationSetPtr newlocset = NULL;
10415 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010416
Daniel Veillardf06307e2001-07-03 10:35:50 +000010417 /*
10418 * Extract the old locset, and then evaluate the result of the
10419 * expression for all the element in the locset. use it to grow
10420 * up a new locset.
10421 */
10422 CHECK_TYPE0(XPATH_LOCATIONSET);
10423 obj = valuePop(ctxt);
10424 oldlocset = obj->user;
10425 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010426
Daniel Veillardf06307e2001-07-03 10:35:50 +000010427 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10428 ctxt->context->contextSize = 0;
10429 ctxt->context->proximityPosition = 0;
10430 if (op->ch2 != -1)
10431 total +=
10432 xmlXPathCompOpEval(ctxt,
10433 &comp->steps[op->ch2]);
10434 res = valuePop(ctxt);
10435 if (res != NULL)
10436 xmlXPathFreeObject(res);
10437 valuePush(ctxt, obj);
10438 CHECK_ERROR0;
10439 return (total);
10440 }
10441 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010442
Daniel Veillardf06307e2001-07-03 10:35:50 +000010443 for (i = 0; i < oldlocset->locNr; i++) {
10444 /*
10445 * Run the evaluation with a node list made of a
10446 * single item in the nodelocset.
10447 */
10448 ctxt->context->node = oldlocset->locTab[i]->user;
10449 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10450 valuePush(ctxt, tmp);
10451 ctxt->context->contextSize = oldlocset->locNr;
10452 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010453
Daniel Veillardf06307e2001-07-03 10:35:50 +000010454 if (op->ch2 != -1)
10455 total +=
10456 xmlXPathCompOpEval(ctxt,
10457 &comp->steps[op->ch2]);
10458 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010459
Daniel Veillardf06307e2001-07-03 10:35:50 +000010460 /*
10461 * The result of the evaluation need to be tested to
10462 * decided whether the filter succeeded or not
10463 */
10464 res = valuePop(ctxt);
10465 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10466 xmlXPtrLocationSetAdd(newlocset,
10467 xmlXPathObjectCopy
10468 (oldlocset->locTab[i]));
10469 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010470
Daniel Veillardf06307e2001-07-03 10:35:50 +000010471 /*
10472 * Cleanup
10473 */
10474 if (res != NULL)
10475 xmlXPathFreeObject(res);
10476 if (ctxt->value == tmp) {
10477 res = valuePop(ctxt);
10478 xmlXPathFreeObject(res);
10479 }
10480
10481 ctxt->context->node = NULL;
10482 }
10483
10484 /*
10485 * The result is used as the new evaluation locset.
10486 */
10487 xmlXPathFreeObject(obj);
10488 ctxt->context->node = NULL;
10489 ctxt->context->contextSize = -1;
10490 ctxt->context->proximityPosition = -1;
10491 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10492 ctxt->context->node = oldnode;
10493 return (total);
10494 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010495#endif /* LIBXML_XPTR_ENABLED */
10496
Daniel Veillardf06307e2001-07-03 10:35:50 +000010497 /*
10498 * Extract the old set, and then evaluate the result of the
10499 * expression for all the element in the set. use it to grow
10500 * up a new set.
10501 */
10502 CHECK_TYPE0(XPATH_NODESET);
10503 obj = valuePop(ctxt);
10504 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010505
Daniel Veillardf06307e2001-07-03 10:35:50 +000010506 oldnode = ctxt->context->node;
10507 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010508
Daniel Veillardf06307e2001-07-03 10:35:50 +000010509 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10510 ctxt->context->contextSize = 0;
10511 ctxt->context->proximityPosition = 0;
10512 if (op->ch2 != -1)
10513 total +=
10514 xmlXPathCompOpEval(ctxt,
10515 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010516 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010517 res = valuePop(ctxt);
10518 if (res != NULL)
10519 xmlXPathFreeObject(res);
10520 valuePush(ctxt, obj);
10521 ctxt->context->node = oldnode;
10522 CHECK_ERROR0;
10523 } else {
10524 /*
10525 * Initialize the new set.
10526 */
10527 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010528
Daniel Veillardf06307e2001-07-03 10:35:50 +000010529 for (i = 0; i < oldset->nodeNr; i++) {
10530 /*
10531 * Run the evaluation with a node list made of
10532 * a single item in the nodeset.
10533 */
10534 ctxt->context->node = oldset->nodeTab[i];
10535 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10536 valuePush(ctxt, tmp);
10537 ctxt->context->contextSize = oldset->nodeNr;
10538 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010539
Daniel Veillardf06307e2001-07-03 10:35:50 +000010540 if (op->ch2 != -1)
10541 total +=
10542 xmlXPathCompOpEval(ctxt,
10543 &comp->steps[op->ch2]);
10544 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010545
Daniel Veillardf06307e2001-07-03 10:35:50 +000010546 /*
William M. Brack08171912003-12-29 02:52:11 +000010547 * The result of the evaluation needs to be tested to
10548 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010549 */
10550 res = valuePop(ctxt);
10551 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10552 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10553 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010554
Daniel Veillardf06307e2001-07-03 10:35:50 +000010555 /*
10556 * Cleanup
10557 */
10558 if (res != NULL)
10559 xmlXPathFreeObject(res);
10560 if (ctxt->value == tmp) {
10561 res = valuePop(ctxt);
10562 xmlXPathFreeObject(res);
10563 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010564
Daniel Veillardf06307e2001-07-03 10:35:50 +000010565 ctxt->context->node = NULL;
10566 }
10567
10568 /*
10569 * The result is used as the new evaluation set.
10570 */
10571 xmlXPathFreeObject(obj);
10572 ctxt->context->node = NULL;
10573 ctxt->context->contextSize = -1;
10574 ctxt->context->proximityPosition = -1;
10575 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10576 }
10577 ctxt->context->node = oldnode;
10578 return (total);
10579 }
10580 case XPATH_OP_SORT:
10581 if (op->ch1 != -1)
10582 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010583 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010584 if ((ctxt->value != NULL) &&
10585 (ctxt->value->type == XPATH_NODESET) &&
10586 (ctxt->value->nodesetval != NULL))
10587 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10588 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010589#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010590 case XPATH_OP_RANGETO:{
10591 xmlXPathObjectPtr range;
10592 xmlXPathObjectPtr res, obj;
10593 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010594 xmlLocationSetPtr newlocset = NULL;
10595 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010596 xmlNodeSetPtr oldset;
10597 int i;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010598
Daniel Veillardf06307e2001-07-03 10:35:50 +000010599 if (op->ch1 != -1)
10600 total +=
10601 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10602 if (op->ch2 == -1)
10603 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010604
William M. Brack08171912003-12-29 02:52:11 +000010605 if (ctxt->value->type == XPATH_LOCATIONSET) {
10606 /*
10607 * Extract the old locset, and then evaluate the result of the
10608 * expression for all the element in the locset. use it to grow
10609 * up a new locset.
10610 */
10611 CHECK_TYPE0(XPATH_LOCATIONSET);
10612 obj = valuePop(ctxt);
10613 oldlocset = obj->user;
10614 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010615
William M. Brack08171912003-12-29 02:52:11 +000010616 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10617 ctxt->context->contextSize = 0;
10618 ctxt->context->proximityPosition = 0;
10619 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10620 res = valuePop(ctxt);
10621 if (res != NULL)
10622 xmlXPathFreeObject(res);
10623 valuePush(ctxt, obj);
10624 CHECK_ERROR0;
10625 return (total);
10626 }
10627 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010628
William M. Brack08171912003-12-29 02:52:11 +000010629 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010630 /*
William M. Brack08171912003-12-29 02:52:11 +000010631 * Run the evaluation with a node list made of a
10632 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010633 */
William M. Brack08171912003-12-29 02:52:11 +000010634 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010635 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10636 valuePush(ctxt, tmp);
William M. Brack08171912003-12-29 02:52:11 +000010637 ctxt->context->contextSize = oldlocset->locNr;
10638 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010639
Daniel Veillardf06307e2001-07-03 10:35:50 +000010640 if (op->ch2 != -1)
10641 total +=
10642 xmlXPathCompOpEval(ctxt,
10643 &comp->steps[op->ch2]);
10644 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010645
Daniel Veillardf06307e2001-07-03 10:35:50 +000010646 /*
10647 * The result of the evaluation need to be tested to
10648 * decided whether the filter succeeded or not
10649 */
10650 res = valuePop(ctxt);
William M. Brack08171912003-12-29 02:52:11 +000010651 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10652 xmlXPtrLocationSetAdd(newlocset,
10653 xmlXPathObjectCopy
10654 (oldlocset->locTab[i]));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010655 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010656
Daniel Veillardf06307e2001-07-03 10:35:50 +000010657 /*
10658 * Cleanup
10659 */
10660 if (res != NULL)
10661 xmlXPathFreeObject(res);
10662 if (ctxt->value == tmp) {
10663 res = valuePop(ctxt);
10664 xmlXPathFreeObject(res);
10665 }
10666
10667 ctxt->context->node = NULL;
10668 }
William M. Brack08171912003-12-29 02:52:11 +000010669 } else { /* Not a location set */
10670 CHECK_TYPE0(XPATH_NODESET);
10671 obj = valuePop(ctxt);
10672 oldset = obj->nodesetval;
10673 ctxt->context->node = NULL;
10674
10675 newlocset = xmlXPtrLocationSetCreate(NULL);
10676
10677 if (oldset != NULL) {
10678 for (i = 0; i < oldset->nodeNr; i++) {
10679 /*
10680 * Run the evaluation with a node list made of a single item
10681 * in the nodeset.
10682 */
10683 ctxt->context->node = oldset->nodeTab[i];
10684 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10685 valuePush(ctxt, tmp);
10686
10687 if (op->ch2 != -1)
10688 total +=
10689 xmlXPathCompOpEval(ctxt,
10690 &comp->steps[op->ch2]);
10691 CHECK_ERROR0;
10692
10693 /*
10694 * The result of the evaluation need to be tested to
10695 * decided whether the filter succeeded or not
10696 */
10697 res = valuePop(ctxt);
10698 range =
10699 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10700 res);
10701 if (range != NULL) {
10702 xmlXPtrLocationSetAdd(newlocset, range);
10703 }
10704
10705 /*
10706 * Cleanup
10707 */
10708 if (res != NULL)
10709 xmlXPathFreeObject(res);
10710 if (ctxt->value == tmp) {
10711 res = valuePop(ctxt);
10712 xmlXPathFreeObject(res);
10713 }
10714
10715 ctxt->context->node = NULL;
10716 }
10717 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010718 }
10719
10720 /*
10721 * The result is used as the new evaluation set.
10722 */
10723 xmlXPathFreeObject(obj);
10724 ctxt->context->node = NULL;
10725 ctxt->context->contextSize = -1;
10726 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010727 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010728 return (total);
10729 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010730#endif /* LIBXML_XPTR_ENABLED */
10731 }
10732 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010733 "XPath: unknown precompiled operation %d\n", op->op);
10734 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010735}
10736
10737/**
10738 * xmlXPathRunEval:
10739 * @ctxt: the XPath parser context with the compiled expression
10740 *
10741 * Evaluate the Precompiled XPath expression in the given context.
10742 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010743static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010744xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10745 xmlXPathCompExprPtr comp;
10746
10747 if ((ctxt == NULL) || (ctxt->comp == NULL))
10748 return;
10749
10750 if (ctxt->valueTab == NULL) {
10751 /* Allocate the value stack */
10752 ctxt->valueTab = (xmlXPathObjectPtr *)
10753 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10754 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010755 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010756 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010757 }
10758 ctxt->valueNr = 0;
10759 ctxt->valueMax = 10;
10760 ctxt->value = NULL;
10761 }
10762 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010763 if(comp->last < 0) {
10764 xmlGenericError(xmlGenericErrorContext,
10765 "xmlXPathRunEval: last is less than zero\n");
10766 return;
10767 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010768 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10769}
10770
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010771/************************************************************************
10772 * *
10773 * Public interfaces *
10774 * *
10775 ************************************************************************/
10776
10777/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010778 * xmlXPathEvalPredicate:
10779 * @ctxt: the XPath context
10780 * @res: the Predicate Expression evaluation result
10781 *
10782 * Evaluate a predicate result for the current node.
10783 * A PredicateExpr is evaluated by evaluating the Expr and converting
10784 * the result to a boolean. If the result is a number, the result will
10785 * be converted to true if the number is equal to the position of the
10786 * context node in the context node list (as returned by the position
10787 * function) and will be converted to false otherwise; if the result
10788 * is not a number, then the result will be converted as if by a call
10789 * to the boolean function.
10790 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010791 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010792 */
10793int
10794xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10795 if (res == NULL) return(0);
10796 switch (res->type) {
10797 case XPATH_BOOLEAN:
10798 return(res->boolval);
10799 case XPATH_NUMBER:
10800 return(res->floatval == ctxt->proximityPosition);
10801 case XPATH_NODESET:
10802 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010803 if (res->nodesetval == NULL)
10804 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010805 return(res->nodesetval->nodeNr != 0);
10806 case XPATH_STRING:
10807 return((res->stringval != NULL) &&
10808 (xmlStrlen(res->stringval) != 0));
10809 default:
10810 STRANGE
10811 }
10812 return(0);
10813}
10814
10815/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010816 * xmlXPathEvaluatePredicateResult:
10817 * @ctxt: the XPath Parser context
10818 * @res: the Predicate Expression evaluation result
10819 *
10820 * Evaluate a predicate result for the current node.
10821 * A PredicateExpr is evaluated by evaluating the Expr and converting
10822 * the result to a boolean. If the result is a number, the result will
10823 * be converted to true if the number is equal to the position of the
10824 * context node in the context node list (as returned by the position
10825 * function) and will be converted to false otherwise; if the result
10826 * is not a number, then the result will be converted as if by a call
10827 * to the boolean function.
10828 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010829 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010830 */
10831int
10832xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10833 xmlXPathObjectPtr res) {
10834 if (res == NULL) return(0);
10835 switch (res->type) {
10836 case XPATH_BOOLEAN:
10837 return(res->boolval);
10838 case XPATH_NUMBER:
10839 return(res->floatval == ctxt->context->proximityPosition);
10840 case XPATH_NODESET:
10841 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010842 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010843 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010844 return(res->nodesetval->nodeNr != 0);
10845 case XPATH_STRING:
10846 return((res->stringval != NULL) &&
10847 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000010848#ifdef LIBXML_XPTR_ENABLED
10849 case XPATH_LOCATIONSET:{
10850 xmlLocationSetPtr ptr = res->user;
10851 if (ptr == NULL)
10852 return(0);
10853 return (ptr->locNr != 0);
10854 }
10855#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010856 default:
10857 STRANGE
10858 }
10859 return(0);
10860}
10861
10862/**
10863 * xmlXPathCompile:
10864 * @str: the XPath expression
10865 *
10866 * Compile an XPath expression
10867 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000010868 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010869 * the caller has to free the object.
10870 */
10871xmlXPathCompExprPtr
10872xmlXPathCompile(const xmlChar *str) {
10873 xmlXPathParserContextPtr ctxt;
10874 xmlXPathCompExprPtr comp;
10875
10876 xmlXPathInit();
10877
10878 ctxt = xmlXPathNewParserContext(str, NULL);
10879 xmlXPathCompileExpr(ctxt);
Daniel Veillardae9733a2003-10-28 19:02:21 +000010880
10881 if( ctxt->error != XPATH_EXPRESSION_OK )
10882 {
10883 xmlXPathFreeParserContext(ctxt);
10884 return (0);
10885 }
10886
Daniel Veillard40af6492001-04-22 08:50:55 +000010887 if (*ctxt->cur != 0) {
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010888 /*
10889 * aleksey: in some cases this line prints *second* error message
10890 * (see bug #78858) and probably this should be fixed.
10891 * However, we are not sure that all error messages are printed
10892 * out in other places. It's not critical so we leave it as-is for now
10893 */
Daniel Veillard40af6492001-04-22 08:50:55 +000010894 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10895 comp = NULL;
10896 } else {
10897 comp = ctxt->comp;
10898 ctxt->comp = NULL;
10899 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010900 xmlXPathFreeParserContext(ctxt);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010901 if (comp != NULL) {
Daniel Veillardceb09b92002-10-04 11:46:37 +000010902 comp->expr = xmlStrdup(str);
10903#ifdef DEBUG_EVAL_COUNTS
Daniel Veillardf06307e2001-07-03 10:35:50 +000010904 comp->string = xmlStrdup(str);
10905 comp->nb = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010906#endif
Daniel Veillardceb09b92002-10-04 11:46:37 +000010907 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010908 return(comp);
10909}
10910
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010911/**
10912 * xmlXPathCompiledEval:
10913 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000010914 * @ctx: the XPath context
10915 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010916 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000010917 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010918 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000010919 * the caller has to free the object.
10920 */
10921xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010922xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000010923 xmlXPathParserContextPtr ctxt;
10924 xmlXPathObjectPtr res, tmp, init = NULL;
10925 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000010926#ifndef LIBXML_THREAD_ENABLED
10927 static int reentance = 0;
10928#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010929
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010930 if ((comp == NULL) || (ctx == NULL))
10931 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010932 xmlXPathInit();
10933
10934 CHECK_CONTEXT(ctx)
10935
Daniel Veillard81463942001-10-16 12:34:39 +000010936#ifndef LIBXML_THREAD_ENABLED
10937 reentance++;
10938 if (reentance > 1)
10939 xmlXPathDisableOptimizer = 1;
10940#endif
10941
Daniel Veillardf06307e2001-07-03 10:35:50 +000010942#ifdef DEBUG_EVAL_COUNTS
10943 comp->nb++;
10944 if ((comp->string != NULL) && (comp->nb > 100)) {
10945 fprintf(stderr, "100 x %s\n", comp->string);
10946 comp->nb = 0;
10947 }
10948#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010949 ctxt = xmlXPathCompParserContext(comp, ctx);
10950 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010951
10952 if (ctxt->value == NULL) {
10953 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010954 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000010955 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000010956 } else {
10957 res = valuePop(ctxt);
10958 }
10959
Daniel Veillardf06307e2001-07-03 10:35:50 +000010960
Owen Taylor3473f882001-02-23 17:55:21 +000010961 do {
10962 tmp = valuePop(ctxt);
10963 if (tmp != NULL) {
10964 if (tmp != init)
10965 stack++;
10966 xmlXPathFreeObject(tmp);
10967 }
10968 } while (tmp != NULL);
10969 if ((stack != 0) && (res != NULL)) {
10970 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010971 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000010972 stack);
10973 }
10974 if (ctxt->error != XPATH_EXPRESSION_OK) {
10975 xmlXPathFreeObject(res);
10976 res = NULL;
10977 }
10978
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010979
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010980 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010981 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000010982#ifndef LIBXML_THREAD_ENABLED
10983 reentance--;
10984#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010985 return(res);
10986}
10987
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010988/**
10989 * xmlXPathEvalExpr:
10990 * @ctxt: the XPath Parser context
10991 *
10992 * Parse and evaluate an XPath expression in the given context,
10993 * then push the result on the context stack
10994 */
10995void
10996xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10997 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010998 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010999 xmlXPathRunEval(ctxt);
11000}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011001
11002/**
11003 * xmlXPathEval:
11004 * @str: the XPath expression
11005 * @ctx: the XPath context
11006 *
11007 * Evaluate the XPath Location Path in the given context.
11008 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011009 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011010 * the caller has to free the object.
11011 */
11012xmlXPathObjectPtr
11013xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11014 xmlXPathParserContextPtr ctxt;
11015 xmlXPathObjectPtr res, tmp, init = NULL;
11016 int stack = 0;
11017
11018 xmlXPathInit();
11019
11020 CHECK_CONTEXT(ctx)
11021
11022 ctxt = xmlXPathNewParserContext(str, ctx);
11023 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011024
11025 if (ctxt->value == NULL) {
11026 xmlGenericError(xmlGenericErrorContext,
11027 "xmlXPathEval: evaluation failed\n");
11028 res = NULL;
11029 } else if (*ctxt->cur != 0) {
11030 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11031 res = NULL;
11032 } else {
11033 res = valuePop(ctxt);
11034 }
11035
11036 do {
11037 tmp = valuePop(ctxt);
11038 if (tmp != NULL) {
11039 if (tmp != init)
11040 stack++;
11041 xmlXPathFreeObject(tmp);
11042 }
11043 } while (tmp != NULL);
11044 if ((stack != 0) && (res != NULL)) {
11045 xmlGenericError(xmlGenericErrorContext,
11046 "xmlXPathEval: %d object left on the stack\n",
11047 stack);
11048 }
11049 if (ctxt->error != XPATH_EXPRESSION_OK) {
11050 xmlXPathFreeObject(res);
11051 res = NULL;
11052 }
11053
Owen Taylor3473f882001-02-23 17:55:21 +000011054 xmlXPathFreeParserContext(ctxt);
11055 return(res);
11056}
11057
11058/**
11059 * xmlXPathEvalExpression:
11060 * @str: the XPath expression
11061 * @ctxt: the XPath context
11062 *
11063 * Evaluate the XPath expression in the given context.
11064 *
11065 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11066 * the caller has to free the object.
11067 */
11068xmlXPathObjectPtr
11069xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11070 xmlXPathParserContextPtr pctxt;
11071 xmlXPathObjectPtr res, tmp;
11072 int stack = 0;
11073
11074 xmlXPathInit();
11075
11076 CHECK_CONTEXT(ctxt)
11077
11078 pctxt = xmlXPathNewParserContext(str, ctxt);
11079 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011080
11081 if (*pctxt->cur != 0) {
11082 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11083 res = NULL;
11084 } else {
11085 res = valuePop(pctxt);
11086 }
11087 do {
11088 tmp = valuePop(pctxt);
11089 if (tmp != NULL) {
11090 xmlXPathFreeObject(tmp);
11091 stack++;
11092 }
11093 } while (tmp != NULL);
11094 if ((stack != 0) && (res != NULL)) {
11095 xmlGenericError(xmlGenericErrorContext,
11096 "xmlXPathEvalExpression: %d object left on the stack\n",
11097 stack);
11098 }
11099 xmlXPathFreeParserContext(pctxt);
11100 return(res);
11101}
11102
Daniel Veillard42766c02002-08-22 20:52:17 +000011103/************************************************************************
11104 * *
11105 * Extra functions not pertaining to the XPath spec *
11106 * *
11107 ************************************************************************/
11108/**
11109 * xmlXPathEscapeUriFunction:
11110 * @ctxt: the XPath Parser context
11111 * @nargs: the number of arguments
11112 *
11113 * Implement the escape-uri() XPath function
11114 * string escape-uri(string $str, bool $escape-reserved)
11115 *
11116 * This function applies the URI escaping rules defined in section 2 of [RFC
11117 * 2396] to the string supplied as $uri-part, which typically represents all
11118 * or part of a URI. The effect of the function is to replace any special
11119 * character in the string by an escape sequence of the form %xx%yy...,
11120 * where xxyy... is the hexadecimal representation of the octets used to
11121 * represent the character in UTF-8.
11122 *
11123 * The set of characters that are escaped depends on the setting of the
11124 * boolean argument $escape-reserved.
11125 *
11126 * If $escape-reserved is true, all characters are escaped other than lower
11127 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11128 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11129 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11130 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11131 * A-F).
11132 *
11133 * If $escape-reserved is false, the behavior differs in that characters
11134 * referred to in [RFC 2396] as reserved characters are not escaped. These
11135 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11136 *
11137 * [RFC 2396] does not define whether escaped URIs should use lower case or
11138 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11139 * compared using string comparison functions, this function must always use
11140 * the upper-case letters A-F.
11141 *
11142 * Generally, $escape-reserved should be set to true when escaping a string
11143 * that is to form a single part of a URI, and to false when escaping an
11144 * entire URI or URI reference.
11145 *
11146 * In the case of non-ascii characters, the string is encoded according to
11147 * utf-8 and then converted according to RFC 2396.
11148 *
11149 * Examples
11150 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11151 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11152 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11153 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11154 *
11155 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011156static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011157xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11158 xmlXPathObjectPtr str;
11159 int escape_reserved;
11160 xmlBufferPtr target;
11161 xmlChar *cptr;
11162 xmlChar escape[4];
11163
11164 CHECK_ARITY(2);
11165
11166 escape_reserved = xmlXPathPopBoolean(ctxt);
11167
11168 CAST_TO_STRING;
11169 str = valuePop(ctxt);
11170
11171 target = xmlBufferCreate();
11172
11173 escape[0] = '%';
11174 escape[3] = 0;
11175
11176 if (target) {
11177 for (cptr = str->stringval; *cptr; cptr++) {
11178 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11179 (*cptr >= 'a' && *cptr <= 'z') ||
11180 (*cptr >= '0' && *cptr <= '9') ||
11181 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11182 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11183 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11184 (*cptr == '%' &&
11185 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11186 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11187 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11188 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11189 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11190 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11191 (!escape_reserved &&
11192 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11193 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11194 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11195 *cptr == ','))) {
11196 xmlBufferAdd(target, cptr, 1);
11197 } else {
11198 if ((*cptr >> 4) < 10)
11199 escape[1] = '0' + (*cptr >> 4);
11200 else
11201 escape[1] = 'A' - 10 + (*cptr >> 4);
11202 if ((*cptr & 0xF) < 10)
11203 escape[2] = '0' + (*cptr & 0xF);
11204 else
11205 escape[2] = 'A' - 10 + (*cptr & 0xF);
11206
11207 xmlBufferAdd(target, &escape[0], 3);
11208 }
11209 }
11210 }
11211 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11212 xmlBufferFree(target);
11213 xmlXPathFreeObject(str);
11214}
11215
Owen Taylor3473f882001-02-23 17:55:21 +000011216/**
11217 * xmlXPathRegisterAllFunctions:
11218 * @ctxt: the XPath context
11219 *
11220 * Registers all default XPath functions in this context
11221 */
11222void
11223xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11224{
11225 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11226 xmlXPathBooleanFunction);
11227 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11228 xmlXPathCeilingFunction);
11229 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11230 xmlXPathCountFunction);
11231 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11232 xmlXPathConcatFunction);
11233 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11234 xmlXPathContainsFunction);
11235 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11236 xmlXPathIdFunction);
11237 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11238 xmlXPathFalseFunction);
11239 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11240 xmlXPathFloorFunction);
11241 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11242 xmlXPathLastFunction);
11243 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11244 xmlXPathLangFunction);
11245 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11246 xmlXPathLocalNameFunction);
11247 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11248 xmlXPathNotFunction);
11249 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11250 xmlXPathNameFunction);
11251 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11252 xmlXPathNamespaceURIFunction);
11253 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11254 xmlXPathNormalizeFunction);
11255 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11256 xmlXPathNumberFunction);
11257 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11258 xmlXPathPositionFunction);
11259 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11260 xmlXPathRoundFunction);
11261 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11262 xmlXPathStringFunction);
11263 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11264 xmlXPathStringLengthFunction);
11265 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11266 xmlXPathStartsWithFunction);
11267 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11268 xmlXPathSubstringFunction);
11269 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11270 xmlXPathSubstringBeforeFunction);
11271 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11272 xmlXPathSubstringAfterFunction);
11273 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11274 xmlXPathSumFunction);
11275 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11276 xmlXPathTrueFunction);
11277 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11278 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011279
11280 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11281 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11282 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011283}
11284
11285#endif /* LIBXML_XPATH_ENABLED */