blob: fad8c26ccad9a4e05bc3cf78492653f3227a1bb9 [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
William M. Brackd1757ab2004-10-02 22:07:48 +000060/*
61 * TODO:
62 * There are a few spots where some tests are done which depend upon ascii
63 * data. These should be enhanced for full UTF8 support (see particularly
64 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
65 */
66
Daniel Veillard4432df22003-09-28 18:58:27 +000067#if defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000068/************************************************************************
69 * *
70 * Floating point stuff *
71 * *
72 ************************************************************************/
73
Daniel Veillardc0631a62001-09-20 13:56:06 +000074#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000075#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000076#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000077#include "trionan.c"
78
Owen Taylor3473f882001-02-23 17:55:21 +000079/*
Owen Taylor3473f882001-02-23 17:55:21 +000080 * The lack of portability of this section of the libc is annoying !
81 */
82double xmlXPathNAN = 0;
83double xmlXPathPINF = 1;
84double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000085double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000086static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000087
Owen Taylor3473f882001-02-23 17:55:21 +000088/**
89 * xmlXPathInit:
90 *
91 * Initialize the XPath environment
92 */
93void
94xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +000095 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +000096
Bjorn Reese45029602001-08-21 09:23:53 +000097 xmlXPathPINF = trio_pinf();
98 xmlXPathNINF = trio_ninf();
99 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000100 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000101
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000102 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000103}
104
Daniel Veillardcda96922001-08-21 10:56:31 +0000105/**
106 * xmlXPathIsNaN:
107 * @val: a double value
108 *
109 * Provides a portable isnan() function to detect whether a double
110 * is a NotaNumber. Based on trio code
111 * http://sourceforge.net/projects/ctrio/
112 *
113 * Returns 1 if the value is a NaN, 0 otherwise
114 */
115int
116xmlXPathIsNaN(double val) {
117 return(trio_isnan(val));
118}
119
120/**
121 * xmlXPathIsInf:
122 * @val: a double value
123 *
124 * Provides a portable isinf() function to detect whether a double
125 * is a +Infinite or -Infinite. Based on trio code
126 * http://sourceforge.net/projects/ctrio/
127 *
128 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
129 */
130int
131xmlXPathIsInf(double val) {
132 return(trio_isinf(val));
133}
134
Daniel Veillard4432df22003-09-28 18:58:27 +0000135#endif /* SCHEMAS or XPATH */
136#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000137/**
138 * xmlXPathGetSign:
139 * @val: a double value
140 *
141 * Provides a portable function to detect the sign of a double
142 * Modified from trio code
143 * http://sourceforge.net/projects/ctrio/
144 *
145 * Returns 1 if the value is Negative, 0 if positive
146 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000147static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000148xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000149 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000150}
151
152
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000153/*
154 * TODO: when compatibility allows remove all "fake node libxslt" strings
155 * the test should just be name[0] = ' '
156 */
157/* #define DEBUG */
158/* #define DEBUG_STEP */
159/* #define DEBUG_STEP_NTH */
160/* #define DEBUG_EXPR */
161/* #define DEBUG_EVAL_COUNTS */
162
163static xmlNs xmlXPathXMLNamespaceStruct = {
164 NULL,
165 XML_NAMESPACE_DECL,
166 XML_XML_NAMESPACE,
167 BAD_CAST "xml",
168 NULL
169};
170static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
171#ifndef LIBXML_THREAD_ENABLED
172/*
173 * Optimizer is disabled only when threaded apps are detected while
174 * the library ain't compiled for thread safety.
175 */
176static int xmlXPathDisableOptimizer = 0;
177#endif
178
Owen Taylor3473f882001-02-23 17:55:21 +0000179/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000180 * *
181 * Error handling routines *
182 * *
183 ************************************************************************/
184
William M. Brack08171912003-12-29 02:52:11 +0000185/*
186 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
187 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000188static const char *xmlXPathErrorMessages[] = {
189 "Ok\n",
190 "Number encoding\n",
191 "Unfinished literal\n",
192 "Start of literal\n",
193 "Expected $ for variable reference\n",
194 "Undefined variable\n",
195 "Invalid predicate\n",
196 "Invalid expression\n",
197 "Missing closing curly brace\n",
198 "Unregistered function\n",
199 "Invalid operand\n",
200 "Invalid type\n",
201 "Invalid number of arguments\n",
202 "Invalid context size\n",
203 "Invalid context position\n",
204 "Memory allocation error\n",
205 "Syntax error\n",
206 "Resource error\n",
207 "Sub resource error\n",
208 "Undefined namespace prefix\n",
209 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000210 "Char out of XML range\n",
211 "Invalid or inclomplete context\n"
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000212};
213
214
215/**
216 * xmlXPathErrMemory:
217 * @ctxt: an XPath context
218 * @extra: extra informations
219 *
220 * Handle a redefinition of attribute error
221 */
222static void
223xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
224{
225 if (ctxt != NULL) {
226 if (extra) {
227 xmlChar buf[200];
228
229 xmlStrPrintf(buf, 200,
230 BAD_CAST "Memory allocation failed : %s\n",
231 extra);
232 ctxt->lastError.message = (char *) xmlStrdup(buf);
233 } else {
234 ctxt->lastError.message = (char *)
235 xmlStrdup(BAD_CAST "Memory allocation failed\n");
236 }
237 ctxt->lastError.domain = XML_FROM_XPATH;
238 ctxt->lastError.code = XML_ERR_NO_MEMORY;
239 if (ctxt->error != NULL)
240 ctxt->error(ctxt->userData, &ctxt->lastError);
241 } else {
242 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000243 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000244 NULL, NULL, XML_FROM_XPATH,
245 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
246 extra, NULL, NULL, 0, 0,
247 "Memory allocation failed : %s\n", extra);
248 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000249 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000250 NULL, NULL, XML_FROM_XPATH,
251 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
252 NULL, NULL, NULL, 0, 0,
253 "Memory allocation failed\n");
254 }
255}
256
257/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000258 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000259 * @ctxt: an XPath parser context
260 * @extra: extra informations
261 *
262 * Handle a redefinition of attribute error
263 */
264static void
265xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
266{
267 ctxt->error = XPATH_MEMORY_ERROR;
268 if (ctxt == NULL)
269 xmlXPathErrMemory(NULL, extra);
270 else
271 xmlXPathErrMemory(ctxt->context, extra);
272}
273
274/**
275 * xmlXPathErr:
276 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000277 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000278 *
279 * Handle a Relax NG Parsing error
280 */
281void
282xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
283{
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000284 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000285 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000286 NULL, NULL, XML_FROM_XPATH,
287 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
288 XML_ERR_ERROR, NULL, 0,
289 NULL, NULL, NULL, 0, 0,
290 xmlXPathErrorMessages[error]);
291 return;
292 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000293 ctxt->error = error;
294 if (ctxt->context == NULL) {
295 __xmlRaiseError(NULL, NULL, NULL,
296 NULL, NULL, XML_FROM_XPATH,
297 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
298 XML_ERR_ERROR, NULL, 0,
299 (const char *) ctxt->base, NULL, NULL,
300 ctxt->cur - ctxt->base, 0,
301 xmlXPathErrorMessages[error]);
302 return;
303 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000304 ctxt->context->lastError.domain = XML_FROM_XPATH;
305 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
306 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000307 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000308 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
309 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
310 ctxt->context->lastError.node = ctxt->context->debugNode;
311 if (ctxt->context->error != NULL) {
312 ctxt->context->error(ctxt->context->userData,
313 &ctxt->context->lastError);
314 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000315 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000316 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
317 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
318 XML_ERR_ERROR, NULL, 0,
319 (const char *) ctxt->base, NULL, NULL,
320 ctxt->cur - ctxt->base, 0,
321 xmlXPathErrorMessages[error]);
322 }
323
324}
325
326/**
327 * xmlXPatherror:
328 * @ctxt: the XPath Parser context
329 * @file: the file name
330 * @line: the line number
331 * @no: the error number
332 *
333 * Formats an error message.
334 */
335void
336xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
337 int line ATTRIBUTE_UNUSED, int no) {
338 xmlXPathErr(ctxt, no);
339}
340
341
342/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000343 * *
344 * Parser Types *
345 * *
346 ************************************************************************/
347
348/*
349 * Types are private:
350 */
351
352typedef enum {
353 XPATH_OP_END=0,
354 XPATH_OP_AND,
355 XPATH_OP_OR,
356 XPATH_OP_EQUAL,
357 XPATH_OP_CMP,
358 XPATH_OP_PLUS,
359 XPATH_OP_MULT,
360 XPATH_OP_UNION,
361 XPATH_OP_ROOT,
362 XPATH_OP_NODE,
363 XPATH_OP_RESET,
364 XPATH_OP_COLLECT,
365 XPATH_OP_VALUE,
366 XPATH_OP_VARIABLE,
367 XPATH_OP_FUNCTION,
368 XPATH_OP_ARG,
369 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000370 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000371 XPATH_OP_SORT
372#ifdef LIBXML_XPTR_ENABLED
373 ,XPATH_OP_RANGETO
374#endif
375} xmlXPathOp;
376
377typedef enum {
378 AXIS_ANCESTOR = 1,
379 AXIS_ANCESTOR_OR_SELF,
380 AXIS_ATTRIBUTE,
381 AXIS_CHILD,
382 AXIS_DESCENDANT,
383 AXIS_DESCENDANT_OR_SELF,
384 AXIS_FOLLOWING,
385 AXIS_FOLLOWING_SIBLING,
386 AXIS_NAMESPACE,
387 AXIS_PARENT,
388 AXIS_PRECEDING,
389 AXIS_PRECEDING_SIBLING,
390 AXIS_SELF
391} xmlXPathAxisVal;
392
393typedef enum {
394 NODE_TEST_NONE = 0,
395 NODE_TEST_TYPE = 1,
396 NODE_TEST_PI = 2,
397 NODE_TEST_ALL = 3,
398 NODE_TEST_NS = 4,
399 NODE_TEST_NAME = 5
400} xmlXPathTestVal;
401
402typedef enum {
403 NODE_TYPE_NODE = 0,
404 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
405 NODE_TYPE_TEXT = XML_TEXT_NODE,
406 NODE_TYPE_PI = XML_PI_NODE
407} xmlXPathTypeVal;
408
409
410typedef struct _xmlXPathStepOp xmlXPathStepOp;
411typedef xmlXPathStepOp *xmlXPathStepOpPtr;
412struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000413 xmlXPathOp op; /* The identifier of the operation */
414 int ch1; /* First child */
415 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000416 int value;
417 int value2;
418 int value3;
419 void *value4;
420 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000421 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000422 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000423};
424
425struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000426 int nbStep; /* Number of steps in this expression */
427 int maxStep; /* Maximum number of steps allocated */
428 xmlXPathStepOp *steps; /* ops for computation of this expression */
429 int last; /* index of last step in expression */
430 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000431 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000432#ifdef DEBUG_EVAL_COUNTS
433 int nb;
434 xmlChar *string;
435#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000436};
437
438/************************************************************************
439 * *
440 * Parser Type functions *
441 * *
442 ************************************************************************/
443
444/**
445 * xmlXPathNewCompExpr:
446 *
447 * Create a new Xpath component
448 *
449 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
450 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000451static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000452xmlXPathNewCompExpr(void) {
453 xmlXPathCompExprPtr cur;
454
455 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
456 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000457 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000458 return(NULL);
459 }
460 memset(cur, 0, sizeof(xmlXPathCompExpr));
461 cur->maxStep = 10;
462 cur->nbStep = 0;
463 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
464 sizeof(xmlXPathStepOp));
465 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000466 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000467 xmlFree(cur);
468 return(NULL);
469 }
470 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
471 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000472#ifdef DEBUG_EVAL_COUNTS
473 cur->nb = 0;
474#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000475 return(cur);
476}
477
478/**
479 * xmlXPathFreeCompExpr:
480 * @comp: an XPATH comp
481 *
482 * Free up the memory allocated by @comp
483 */
484void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000485xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
486{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000487 xmlXPathStepOpPtr op;
488 int i;
489
490 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000491 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000492 if (comp->dict == NULL) {
493 for (i = 0; i < comp->nbStep; i++) {
494 op = &comp->steps[i];
495 if (op->value4 != NULL) {
496 if (op->op == XPATH_OP_VALUE)
497 xmlXPathFreeObject(op->value4);
498 else
499 xmlFree(op->value4);
500 }
501 if (op->value5 != NULL)
502 xmlFree(op->value5);
503 }
504 } else {
505 for (i = 0; i < comp->nbStep; i++) {
506 op = &comp->steps[i];
507 if (op->value4 != NULL) {
508 if (op->op == XPATH_OP_VALUE)
509 xmlXPathFreeObject(op->value4);
510 }
511 }
512 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000513 }
514 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000515 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000516 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000517#ifdef DEBUG_EVAL_COUNTS
518 if (comp->string != NULL) {
519 xmlFree(comp->string);
520 }
521#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000522 if (comp->expr != NULL) {
523 xmlFree(comp->expr);
524 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000525
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000526 xmlFree(comp);
527}
528
529/**
530 * xmlXPathCompExprAdd:
531 * @comp: the compiled expression
532 * @ch1: first child index
533 * @ch2: second child index
534 * @op: an op
535 * @value: the first int value
536 * @value2: the second int value
537 * @value3: the third int value
538 * @value4: the first string value
539 * @value5: the second string value
540 *
William M. Brack08171912003-12-29 02:52:11 +0000541 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000542 *
543 * Returns -1 in case of failure, the index otherwise
544 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000545static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000546xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
547 xmlXPathOp op, int value,
548 int value2, int value3, void *value4, void *value5) {
549 if (comp->nbStep >= comp->maxStep) {
550 xmlXPathStepOp *real;
551
552 comp->maxStep *= 2;
553 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
554 comp->maxStep * sizeof(xmlXPathStepOp));
555 if (real == NULL) {
556 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000557 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000558 return(-1);
559 }
560 comp->steps = real;
561 }
562 comp->last = comp->nbStep;
563 comp->steps[comp->nbStep].ch1 = ch1;
564 comp->steps[comp->nbStep].ch2 = ch2;
565 comp->steps[comp->nbStep].op = op;
566 comp->steps[comp->nbStep].value = value;
567 comp->steps[comp->nbStep].value2 = value2;
568 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000569 if ((comp->dict != NULL) &&
570 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
571 (op == XPATH_OP_COLLECT))) {
572 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000573 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000574 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000575 xmlFree(value4);
576 } else
577 comp->steps[comp->nbStep].value4 = NULL;
578 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000579 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000580 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000581 xmlFree(value5);
582 } else
583 comp->steps[comp->nbStep].value5 = NULL;
584 } else {
585 comp->steps[comp->nbStep].value4 = value4;
586 comp->steps[comp->nbStep].value5 = value5;
587 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000588 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000589 return(comp->nbStep++);
590}
591
Daniel Veillardf06307e2001-07-03 10:35:50 +0000592/**
593 * xmlXPathCompSwap:
594 * @comp: the compiled expression
595 * @op: operation index
596 *
597 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000598 */
599static void
600xmlXPathCompSwap(xmlXPathStepOpPtr op) {
601 int tmp;
602
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000603#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000604 /*
605 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000606 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000607 * application
608 */
609 if (xmlXPathDisableOptimizer)
610 return;
611#endif
612
Daniel Veillardf06307e2001-07-03 10:35:50 +0000613 tmp = op->ch1;
614 op->ch1 = op->ch2;
615 op->ch2 = tmp;
616}
617
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000618#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
619 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
620 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000621#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
622 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
623 (op), (val), (val2), (val3), (val4), (val5))
624
625#define PUSH_LEAVE_EXPR(op, val, val2) \
626xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
627
628#define PUSH_UNARY_EXPR(op, ch, val, val2) \
629xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
630
631#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000632xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
633 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000634
635/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000636 * *
637 * Debugging related functions *
638 * *
639 ************************************************************************/
640
Owen Taylor3473f882001-02-23 17:55:21 +0000641#define STRANGE \
642 xmlGenericError(xmlGenericErrorContext, \
643 "Internal error at %s:%d\n", \
644 __FILE__, __LINE__);
645
646#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000647static void
648xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000649 int i;
650 char shift[100];
651
652 for (i = 0;((i < depth) && (i < 25));i++)
653 shift[2 * i] = shift[2 * i + 1] = ' ';
654 shift[2 * i] = shift[2 * i + 1] = 0;
655 if (cur == NULL) {
656 fprintf(output, shift);
657 fprintf(output, "Node is NULL !\n");
658 return;
659
660 }
661
662 if ((cur->type == XML_DOCUMENT_NODE) ||
663 (cur->type == XML_HTML_DOCUMENT_NODE)) {
664 fprintf(output, shift);
665 fprintf(output, " /\n");
666 } else if (cur->type == XML_ATTRIBUTE_NODE)
667 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
668 else
669 xmlDebugDumpOneNode(output, cur, depth);
670}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000671static void
672xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000673 xmlNodePtr tmp;
674 int i;
675 char shift[100];
676
677 for (i = 0;((i < depth) && (i < 25));i++)
678 shift[2 * i] = shift[2 * i + 1] = ' ';
679 shift[2 * i] = shift[2 * i + 1] = 0;
680 if (cur == NULL) {
681 fprintf(output, shift);
682 fprintf(output, "Node is NULL !\n");
683 return;
684
685 }
686
687 while (cur != NULL) {
688 tmp = cur;
689 cur = cur->next;
690 xmlDebugDumpOneNode(output, tmp, depth);
691 }
692}
Owen Taylor3473f882001-02-23 17:55:21 +0000693
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000694static void
695xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000696 int i;
697 char shift[100];
698
699 for (i = 0;((i < depth) && (i < 25));i++)
700 shift[2 * i] = shift[2 * i + 1] = ' ';
701 shift[2 * i] = shift[2 * i + 1] = 0;
702
703 if (cur == NULL) {
704 fprintf(output, shift);
705 fprintf(output, "NodeSet is NULL !\n");
706 return;
707
708 }
709
Daniel Veillard911f49a2001-04-07 15:39:35 +0000710 if (cur != NULL) {
711 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
712 for (i = 0;i < cur->nodeNr;i++) {
713 fprintf(output, shift);
714 fprintf(output, "%d", i + 1);
715 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
716 }
Owen Taylor3473f882001-02-23 17:55:21 +0000717 }
718}
719
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000720static void
721xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000722 int i;
723 char shift[100];
724
725 for (i = 0;((i < depth) && (i < 25));i++)
726 shift[2 * i] = shift[2 * i + 1] = ' ';
727 shift[2 * i] = shift[2 * i + 1] = 0;
728
729 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
730 fprintf(output, shift);
731 fprintf(output, "Value Tree is NULL !\n");
732 return;
733
734 }
735
736 fprintf(output, shift);
737 fprintf(output, "%d", i + 1);
738 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
739}
Owen Taylor3473f882001-02-23 17:55:21 +0000740#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000741static void
742xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000743 int i;
744 char shift[100];
745
746 for (i = 0;((i < depth) && (i < 25));i++)
747 shift[2 * i] = shift[2 * i + 1] = ' ';
748 shift[2 * i] = shift[2 * i + 1] = 0;
749
750 if (cur == NULL) {
751 fprintf(output, shift);
752 fprintf(output, "LocationSet is NULL !\n");
753 return;
754
755 }
756
757 for (i = 0;i < cur->locNr;i++) {
758 fprintf(output, shift);
759 fprintf(output, "%d : ", i + 1);
760 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
761 }
762}
Daniel Veillard017b1082001-06-21 11:20:21 +0000763#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000764
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000765/**
766 * xmlXPathDebugDumpObject:
767 * @output: the FILE * to dump the output
768 * @cur: the object to inspect
769 * @depth: indentation level
770 *
771 * Dump the content of the object for debugging purposes
772 */
773void
774xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000775 int i;
776 char shift[100];
777
Daniel Veillarda82b1822004-11-08 16:24:57 +0000778 if (output == NULL) return;
779
Owen Taylor3473f882001-02-23 17:55:21 +0000780 for (i = 0;((i < depth) && (i < 25));i++)
781 shift[2 * i] = shift[2 * i + 1] = ' ';
782 shift[2 * i] = shift[2 * i + 1] = 0;
783
784 fprintf(output, shift);
785
786 if (cur == NULL) {
787 fprintf(output, "Object is empty (NULL)\n");
788 return;
789 }
790 switch(cur->type) {
791 case XPATH_UNDEFINED:
792 fprintf(output, "Object is uninitialized\n");
793 break;
794 case XPATH_NODESET:
795 fprintf(output, "Object is a Node Set :\n");
796 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
797 break;
798 case XPATH_XSLT_TREE:
799 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000800 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000801 break;
802 case XPATH_BOOLEAN:
803 fprintf(output, "Object is a Boolean : ");
804 if (cur->boolval) fprintf(output, "true\n");
805 else fprintf(output, "false\n");
806 break;
807 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000808 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000809 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000810 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000811 break;
812 case -1:
813 fprintf(output, "Object is a number : -Infinity\n");
814 break;
815 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000816 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000817 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000818 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
819 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000820 } else {
821 fprintf(output, "Object is a number : %0g\n", cur->floatval);
822 }
823 }
Owen Taylor3473f882001-02-23 17:55:21 +0000824 break;
825 case XPATH_STRING:
826 fprintf(output, "Object is a string : ");
827 xmlDebugDumpString(output, cur->stringval);
828 fprintf(output, "\n");
829 break;
830 case XPATH_POINT:
831 fprintf(output, "Object is a point : index %d in node", cur->index);
832 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
833 fprintf(output, "\n");
834 break;
835 case XPATH_RANGE:
836 if ((cur->user2 == NULL) ||
837 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
838 fprintf(output, "Object is a collapsed range :\n");
839 fprintf(output, shift);
840 if (cur->index >= 0)
841 fprintf(output, "index %d in ", cur->index);
842 fprintf(output, "node\n");
843 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
844 depth + 1);
845 } else {
846 fprintf(output, "Object is a range :\n");
847 fprintf(output, shift);
848 fprintf(output, "From ");
849 if (cur->index >= 0)
850 fprintf(output, "index %d in ", cur->index);
851 fprintf(output, "node\n");
852 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
853 depth + 1);
854 fprintf(output, shift);
855 fprintf(output, "To ");
856 if (cur->index2 >= 0)
857 fprintf(output, "index %d in ", cur->index2);
858 fprintf(output, "node\n");
859 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
860 depth + 1);
861 fprintf(output, "\n");
862 }
863 break;
864 case XPATH_LOCATIONSET:
865#if defined(LIBXML_XPTR_ENABLED)
866 fprintf(output, "Object is a Location Set:\n");
867 xmlXPathDebugDumpLocationSet(output,
868 (xmlLocationSetPtr) cur->user, depth);
869#endif
870 break;
871 case XPATH_USERS:
872 fprintf(output, "Object is user defined\n");
873 break;
874 }
875}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000876
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000877static void
878xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000879 xmlXPathStepOpPtr op, int depth) {
880 int i;
881 char shift[100];
882
883 for (i = 0;((i < depth) && (i < 25));i++)
884 shift[2 * i] = shift[2 * i + 1] = ' ';
885 shift[2 * i] = shift[2 * i + 1] = 0;
886
887 fprintf(output, shift);
888 if (op == NULL) {
889 fprintf(output, "Step is NULL\n");
890 return;
891 }
892 switch (op->op) {
893 case XPATH_OP_END:
894 fprintf(output, "END"); break;
895 case XPATH_OP_AND:
896 fprintf(output, "AND"); break;
897 case XPATH_OP_OR:
898 fprintf(output, "OR"); break;
899 case XPATH_OP_EQUAL:
900 if (op->value)
901 fprintf(output, "EQUAL =");
902 else
903 fprintf(output, "EQUAL !=");
904 break;
905 case XPATH_OP_CMP:
906 if (op->value)
907 fprintf(output, "CMP <");
908 else
909 fprintf(output, "CMP >");
910 if (!op->value2)
911 fprintf(output, "=");
912 break;
913 case XPATH_OP_PLUS:
914 if (op->value == 0)
915 fprintf(output, "PLUS -");
916 else if (op->value == 1)
917 fprintf(output, "PLUS +");
918 else if (op->value == 2)
919 fprintf(output, "PLUS unary -");
920 else if (op->value == 3)
921 fprintf(output, "PLUS unary - -");
922 break;
923 case XPATH_OP_MULT:
924 if (op->value == 0)
925 fprintf(output, "MULT *");
926 else if (op->value == 1)
927 fprintf(output, "MULT div");
928 else
929 fprintf(output, "MULT mod");
930 break;
931 case XPATH_OP_UNION:
932 fprintf(output, "UNION"); break;
933 case XPATH_OP_ROOT:
934 fprintf(output, "ROOT"); break;
935 case XPATH_OP_NODE:
936 fprintf(output, "NODE"); break;
937 case XPATH_OP_RESET:
938 fprintf(output, "RESET"); break;
939 case XPATH_OP_SORT:
940 fprintf(output, "SORT"); break;
941 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000942 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
943 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
944 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000945 const xmlChar *prefix = op->value4;
946 const xmlChar *name = op->value5;
947
948 fprintf(output, "COLLECT ");
949 switch (axis) {
950 case AXIS_ANCESTOR:
951 fprintf(output, " 'ancestors' "); break;
952 case AXIS_ANCESTOR_OR_SELF:
953 fprintf(output, " 'ancestors-or-self' "); break;
954 case AXIS_ATTRIBUTE:
955 fprintf(output, " 'attributes' "); break;
956 case AXIS_CHILD:
957 fprintf(output, " 'child' "); break;
958 case AXIS_DESCENDANT:
959 fprintf(output, " 'descendant' "); break;
960 case AXIS_DESCENDANT_OR_SELF:
961 fprintf(output, " 'descendant-or-self' "); break;
962 case AXIS_FOLLOWING:
963 fprintf(output, " 'following' "); break;
964 case AXIS_FOLLOWING_SIBLING:
965 fprintf(output, " 'following-siblings' "); break;
966 case AXIS_NAMESPACE:
967 fprintf(output, " 'namespace' "); break;
968 case AXIS_PARENT:
969 fprintf(output, " 'parent' "); break;
970 case AXIS_PRECEDING:
971 fprintf(output, " 'preceding' "); break;
972 case AXIS_PRECEDING_SIBLING:
973 fprintf(output, " 'preceding-sibling' "); break;
974 case AXIS_SELF:
975 fprintf(output, " 'self' "); break;
976 }
977 switch (test) {
978 case NODE_TEST_NONE:
979 fprintf(output, "'none' "); break;
980 case NODE_TEST_TYPE:
981 fprintf(output, "'type' "); break;
982 case NODE_TEST_PI:
983 fprintf(output, "'PI' "); break;
984 case NODE_TEST_ALL:
985 fprintf(output, "'all' "); break;
986 case NODE_TEST_NS:
987 fprintf(output, "'namespace' "); break;
988 case NODE_TEST_NAME:
989 fprintf(output, "'name' "); break;
990 }
991 switch (type) {
992 case NODE_TYPE_NODE:
993 fprintf(output, "'node' "); break;
994 case NODE_TYPE_COMMENT:
995 fprintf(output, "'comment' "); break;
996 case NODE_TYPE_TEXT:
997 fprintf(output, "'text' "); break;
998 case NODE_TYPE_PI:
999 fprintf(output, "'PI' "); break;
1000 }
1001 if (prefix != NULL)
1002 fprintf(output, "%s:", prefix);
1003 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001004 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001005 break;
1006
1007 }
1008 case XPATH_OP_VALUE: {
1009 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1010
1011 fprintf(output, "ELEM ");
1012 xmlXPathDebugDumpObject(output, object, 0);
1013 goto finish;
1014 }
1015 case XPATH_OP_VARIABLE: {
1016 const xmlChar *prefix = op->value5;
1017 const xmlChar *name = op->value4;
1018
1019 if (prefix != NULL)
1020 fprintf(output, "VARIABLE %s:%s", prefix, name);
1021 else
1022 fprintf(output, "VARIABLE %s", name);
1023 break;
1024 }
1025 case XPATH_OP_FUNCTION: {
1026 int nbargs = op->value;
1027 const xmlChar *prefix = op->value5;
1028 const xmlChar *name = op->value4;
1029
1030 if (prefix != NULL)
1031 fprintf(output, "FUNCTION %s:%s(%d args)",
1032 prefix, name, nbargs);
1033 else
1034 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1035 break;
1036 }
1037 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1038 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001039 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001040#ifdef LIBXML_XPTR_ENABLED
1041 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1042#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001043 default:
1044 fprintf(output, "UNKNOWN %d\n", op->op); return;
1045 }
1046 fprintf(output, "\n");
1047finish:
1048 if (op->ch1 >= 0)
1049 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1050 if (op->ch2 >= 0)
1051 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1052}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001053
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001054/**
1055 * xmlXPathDebugDumpCompExpr:
1056 * @output: the FILE * for the output
1057 * @comp: the precompiled XPath expression
1058 * @depth: the indentation level.
1059 *
1060 * Dumps the tree of the compiled XPath expression.
1061 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001062void
1063xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1064 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001065 int i;
1066 char shift[100];
1067
Daniel Veillarda82b1822004-11-08 16:24:57 +00001068 if ((output == NULL) || (comp == NULL)) return;
1069
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001070 for (i = 0;((i < depth) && (i < 25));i++)
1071 shift[2 * i] = shift[2 * i + 1] = ' ';
1072 shift[2 * i] = shift[2 * i + 1] = 0;
1073
1074 fprintf(output, shift);
1075
1076 if (comp == NULL) {
1077 fprintf(output, "Compiled Expression is NULL\n");
1078 return;
1079 }
1080 fprintf(output, "Compiled Expression : %d elements\n",
1081 comp->nbStep);
1082 i = comp->last;
1083 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1084}
Daniel Veillard017b1082001-06-21 11:20:21 +00001085#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001086
1087/************************************************************************
1088 * *
1089 * Parser stacks related functions and macros *
1090 * *
1091 ************************************************************************/
1092
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001093/**
1094 * valuePop:
1095 * @ctxt: an XPath evaluation context
1096 *
1097 * Pops the top XPath object from the value stack
1098 *
1099 * Returns the XPath object just removed
1100 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001101extern xmlXPathObjectPtr
1102valuePop(xmlXPathParserContextPtr ctxt)
1103{
1104 xmlXPathObjectPtr ret;
1105
Daniel Veillarda82b1822004-11-08 16:24:57 +00001106 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard1c732d22002-11-30 11:22:59 +00001107 return (0);
1108 ctxt->valueNr--;
1109 if (ctxt->valueNr > 0)
1110 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1111 else
1112 ctxt->value = NULL;
1113 ret = ctxt->valueTab[ctxt->valueNr];
1114 ctxt->valueTab[ctxt->valueNr] = 0;
1115 return (ret);
1116}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001117/**
1118 * valuePush:
1119 * @ctxt: an XPath evaluation context
1120 * @value: the XPath object
1121 *
1122 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001123 *
1124 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001125 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001126extern int
1127valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1128{
Daniel Veillarda82b1822004-11-08 16:24:57 +00001129 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00001130 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001131 xmlXPathObjectPtr *tmp;
1132
1133 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1134 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00001135 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001136 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00001137 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1138 return (0);
1139 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001140 ctxt->valueMax *= 2;
1141 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00001142 }
1143 ctxt->valueTab[ctxt->valueNr] = value;
1144 ctxt->value = value;
1145 return (ctxt->valueNr++);
1146}
Owen Taylor3473f882001-02-23 17:55:21 +00001147
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001148/**
1149 * xmlXPathPopBoolean:
1150 * @ctxt: an XPath parser context
1151 *
1152 * Pops a boolean from the stack, handling conversion if needed.
1153 * Check error with #xmlXPathCheckError.
1154 *
1155 * Returns the boolean
1156 */
1157int
1158xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1159 xmlXPathObjectPtr obj;
1160 int ret;
1161
1162 obj = valuePop(ctxt);
1163 if (obj == NULL) {
1164 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1165 return(0);
1166 }
William M. Brack08171912003-12-29 02:52:11 +00001167 if (obj->type != XPATH_BOOLEAN)
1168 ret = xmlXPathCastToBoolean(obj);
1169 else
1170 ret = obj->boolval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001171 xmlXPathFreeObject(obj);
1172 return(ret);
1173}
1174
1175/**
1176 * xmlXPathPopNumber:
1177 * @ctxt: an XPath parser context
1178 *
1179 * Pops a number from the stack, handling conversion if needed.
1180 * Check error with #xmlXPathCheckError.
1181 *
1182 * Returns the number
1183 */
1184double
1185xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1186 xmlXPathObjectPtr obj;
1187 double ret;
1188
1189 obj = valuePop(ctxt);
1190 if (obj == NULL) {
1191 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1192 return(0);
1193 }
William M. Brack08171912003-12-29 02:52:11 +00001194 if (obj->type != XPATH_NUMBER)
1195 ret = xmlXPathCastToNumber(obj);
1196 else
1197 ret = obj->floatval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001198 xmlXPathFreeObject(obj);
1199 return(ret);
1200}
1201
1202/**
1203 * xmlXPathPopString:
1204 * @ctxt: an XPath parser context
1205 *
1206 * Pops a string from the stack, handling conversion if needed.
1207 * Check error with #xmlXPathCheckError.
1208 *
1209 * Returns the string
1210 */
1211xmlChar *
1212xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1213 xmlXPathObjectPtr obj;
1214 xmlChar * ret;
1215
1216 obj = valuePop(ctxt);
1217 if (obj == NULL) {
1218 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1219 return(NULL);
1220 }
William M. Brack08171912003-12-29 02:52:11 +00001221 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001222 /* TODO: needs refactoring somewhere else */
1223 if (obj->stringval == ret)
1224 obj->stringval = NULL;
1225 xmlXPathFreeObject(obj);
1226 return(ret);
1227}
1228
1229/**
1230 * xmlXPathPopNodeSet:
1231 * @ctxt: an XPath parser context
1232 *
1233 * Pops a node-set from the stack, handling conversion if needed.
1234 * Check error with #xmlXPathCheckError.
1235 *
1236 * Returns the node-set
1237 */
1238xmlNodeSetPtr
1239xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1240 xmlXPathObjectPtr obj;
1241 xmlNodeSetPtr ret;
1242
Daniel Veillardf2a36f92004-11-08 17:55:01 +00001243 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001244 if (ctxt->value == NULL) {
1245 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1246 return(NULL);
1247 }
1248 if (!xmlXPathStackIsNodeSet(ctxt)) {
1249 xmlXPathSetTypeError(ctxt);
1250 return(NULL);
1251 }
1252 obj = valuePop(ctxt);
1253 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00001254#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00001255 /* to fix memory leak of not clearing obj->user */
1256 if (obj->boolval && obj->user != NULL)
1257 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00001258#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001259 xmlXPathFreeNodeSetList(obj);
1260 return(ret);
1261}
1262
1263/**
1264 * xmlXPathPopExternal:
1265 * @ctxt: an XPath parser context
1266 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001267 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001268 * Check error with #xmlXPathCheckError.
1269 *
1270 * Returns the object
1271 */
1272void *
1273xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1274 xmlXPathObjectPtr obj;
1275 void * ret;
1276
Daniel Veillarda82b1822004-11-08 16:24:57 +00001277 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001278 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1279 return(NULL);
1280 }
1281 if (ctxt->value->type != XPATH_USERS) {
1282 xmlXPathSetTypeError(ctxt);
1283 return(NULL);
1284 }
1285 obj = valuePop(ctxt);
1286 ret = obj->user;
1287 xmlXPathFreeObject(obj);
1288 return(ret);
1289}
1290
Owen Taylor3473f882001-02-23 17:55:21 +00001291/*
1292 * Macros for accessing the content. Those should be used only by the parser,
1293 * and not exported.
1294 *
1295 * Dirty macros, i.e. one need to make assumption on the context to use them
1296 *
1297 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1298 * CUR returns the current xmlChar value, i.e. a 8 bit value
1299 * in ISO-Latin or UTF-8.
1300 * This should be used internally by the parser
1301 * only to compare to ASCII values otherwise it would break when
1302 * running with UTF-8 encoding.
1303 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1304 * to compare on ASCII based substring.
1305 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1306 * strings within the parser.
1307 * CURRENT Returns the current char value, with the full decoding of
1308 * UTF-8 if we are using this mode. It returns an int.
1309 * NEXT Skip to the next character, this does the proper decoding
1310 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1311 * It returns the pointer to the current xmlChar.
1312 */
1313
1314#define CUR (*ctxt->cur)
1315#define SKIP(val) ctxt->cur += (val)
1316#define NXT(val) ctxt->cur[(val)]
1317#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001318#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1319
1320#define COPY_BUF(l,b,i,v) \
1321 if (l == 1) b[i++] = (xmlChar) v; \
1322 else i += xmlCopyChar(l,&b[i],v)
1323
1324#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001325
1326#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001327 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001328
1329#define CURRENT (*ctxt->cur)
1330#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1331
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001332
1333#ifndef DBL_DIG
1334#define DBL_DIG 16
1335#endif
1336#ifndef DBL_EPSILON
1337#define DBL_EPSILON 1E-9
1338#endif
1339
1340#define UPPER_DOUBLE 1E9
1341#define LOWER_DOUBLE 1E-5
1342
1343#define INTEGER_DIGITS DBL_DIG
1344#define FRACTION_DIGITS (DBL_DIG + 1)
1345#define EXPONENT_DIGITS (3 + 2)
1346
1347/**
1348 * xmlXPathFormatNumber:
1349 * @number: number to format
1350 * @buffer: output buffer
1351 * @buffersize: size of output buffer
1352 *
1353 * Convert the number into a string representation.
1354 */
1355static void
1356xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1357{
Daniel Veillardcda96922001-08-21 10:56:31 +00001358 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001359 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001360 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001361 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001362 break;
1363 case -1:
1364 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001365 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001366 break;
1367 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001368 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001369 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001370 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001371 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001372 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001373 } else if (number == ((int) number)) {
1374 char work[30];
1375 char *ptr, *cur;
1376 int res, value = (int) number;
1377
1378 ptr = &buffer[0];
1379 if (value < 0) {
1380 *ptr++ = '-';
1381 value = -value;
1382 }
1383 if (value == 0) {
1384 *ptr++ = '0';
1385 } else {
1386 cur = &work[0];
1387 while (value != 0) {
1388 res = value % 10;
1389 value = value / 10;
1390 *cur++ = '0' + res;
1391 }
1392 cur--;
1393 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1394 *ptr++ = *cur--;
1395 }
1396 }
1397 if (ptr - buffer < buffersize) {
1398 *ptr = 0;
1399 } else if (buffersize > 0) {
1400 ptr--;
1401 *ptr = 0;
1402 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001403 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001404 /* 3 is sign, decimal point, and terminating zero */
1405 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1406 int integer_place, fraction_place;
1407 char *ptr;
1408 char *after_fraction;
1409 double absolute_value;
1410 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001411
Bjorn Reese70a9da52001-04-21 16:57:29 +00001412 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001413
Bjorn Reese70a9da52001-04-21 16:57:29 +00001414 /*
1415 * First choose format - scientific or regular floating point.
1416 * In either case, result is in work, and after_fraction points
1417 * just past the fractional part.
1418 */
1419 if ( ((absolute_value > UPPER_DOUBLE) ||
1420 (absolute_value < LOWER_DOUBLE)) &&
1421 (absolute_value != 0.0) ) {
1422 /* Use scientific notation */
1423 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1424 fraction_place = DBL_DIG - 1;
1425 snprintf(work, sizeof(work),"%*.*e",
1426 integer_place, fraction_place, number);
1427 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001428 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001429 else {
1430 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001431 if (absolute_value > 0.0)
1432 integer_place = 1 + (int)log10(absolute_value);
1433 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001434 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001435 fraction_place = (integer_place > 0)
1436 ? DBL_DIG - integer_place
1437 : DBL_DIG;
1438 size = snprintf(work, sizeof(work), "%0.*f",
1439 fraction_place, number);
1440 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001441 }
1442
Bjorn Reese70a9da52001-04-21 16:57:29 +00001443 /* Remove fractional trailing zeroes */
1444 ptr = after_fraction;
1445 while (*(--ptr) == '0')
1446 ;
1447 if (*ptr != '.')
1448 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001449 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001450
1451 /* Finally copy result back to caller */
1452 size = strlen(work) + 1;
1453 if (size > buffersize) {
1454 work[buffersize - 1] = 0;
1455 size = buffersize;
1456 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001457 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001458 }
1459 break;
1460 }
1461}
1462
Owen Taylor3473f882001-02-23 17:55:21 +00001463
1464/************************************************************************
1465 * *
1466 * Routines to handle NodeSets *
1467 * *
1468 ************************************************************************/
1469
1470/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001471 * xmlXPathOrderDocElems:
1472 * @doc: an input document
1473 *
1474 * Call this routine to speed up XPath computation on static documents.
1475 * This stamps all the element nodes with the document order
1476 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00001477 * field, the value stored is actually - the node number (starting at -1)
1478 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001479 *
William M. Brack08171912003-12-29 02:52:11 +00001480 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001481 * of error.
1482 */
1483long
1484xmlXPathOrderDocElems(xmlDocPtr doc) {
1485 long count = 0;
1486 xmlNodePtr cur;
1487
1488 if (doc == NULL)
1489 return(-1);
1490 cur = doc->children;
1491 while (cur != NULL) {
1492 if (cur->type == XML_ELEMENT_NODE) {
1493 cur->content = (void *) (-(++count));
1494 if (cur->children != NULL) {
1495 cur = cur->children;
1496 continue;
1497 }
1498 }
1499 if (cur->next != NULL) {
1500 cur = cur->next;
1501 continue;
1502 }
1503 do {
1504 cur = cur->parent;
1505 if (cur == NULL)
1506 break;
1507 if (cur == (xmlNodePtr) doc) {
1508 cur = NULL;
1509 break;
1510 }
1511 if (cur->next != NULL) {
1512 cur = cur->next;
1513 break;
1514 }
1515 } while (cur != NULL);
1516 }
1517 return(count);
1518}
1519
1520/**
Owen Taylor3473f882001-02-23 17:55:21 +00001521 * xmlXPathCmpNodes:
1522 * @node1: the first node
1523 * @node2: the second node
1524 *
1525 * Compare two nodes w.r.t document order
1526 *
1527 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00001528 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001529 */
1530int
1531xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1532 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001533 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001534 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001535 xmlNodePtr cur, root;
1536
1537 if ((node1 == NULL) || (node2 == NULL))
1538 return(-2);
1539 /*
1540 * a couple of optimizations which will avoid computations in most cases
1541 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001542 if (node1->type == XML_ATTRIBUTE_NODE) {
1543 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001544 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001545 node1 = node1->parent;
1546 }
1547 if (node2->type == XML_ATTRIBUTE_NODE) {
1548 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001549 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001550 node2 = node2->parent;
1551 }
1552 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001553 if (attr1 == attr2) {
1554 /* not required, but we keep attributes in order */
1555 if (attr1 != 0) {
1556 cur = attrNode2->prev;
1557 while (cur != NULL) {
1558 if (cur == attrNode1)
1559 return (1);
1560 cur = cur->prev;
1561 }
1562 return (-1);
1563 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001564 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001565 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001566 if (attr2 == 1)
1567 return(1);
1568 return(-1);
1569 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001570 if ((node1->type == XML_NAMESPACE_DECL) ||
1571 (node2->type == XML_NAMESPACE_DECL))
1572 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001573 if (node1 == node2->prev)
1574 return(1);
1575 if (node1 == node2->next)
1576 return(-1);
1577
1578 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001579 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001580 */
1581 if ((node1->type == XML_ELEMENT_NODE) &&
1582 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001583 (0 > (long) node1->content) &&
1584 (0 > (long) node2->content) &&
1585 (node1->doc == node2->doc)) {
1586 long l1, l2;
1587
1588 l1 = -((long) node1->content);
1589 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001590 if (l1 < l2)
1591 return(1);
1592 if (l1 > l2)
1593 return(-1);
1594 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001595
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001596 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001597 * compute depth to root
1598 */
1599 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1600 if (cur == node1)
1601 return(1);
1602 depth2++;
1603 }
1604 root = cur;
1605 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1606 if (cur == node2)
1607 return(-1);
1608 depth1++;
1609 }
1610 /*
1611 * Distinct document (or distinct entities :-( ) case.
1612 */
1613 if (root != cur) {
1614 return(-2);
1615 }
1616 /*
1617 * get the nearest common ancestor.
1618 */
1619 while (depth1 > depth2) {
1620 depth1--;
1621 node1 = node1->parent;
1622 }
1623 while (depth2 > depth1) {
1624 depth2--;
1625 node2 = node2->parent;
1626 }
1627 while (node1->parent != node2->parent) {
1628 node1 = node1->parent;
1629 node2 = node2->parent;
1630 /* should not happen but just in case ... */
1631 if ((node1 == NULL) || (node2 == NULL))
1632 return(-2);
1633 }
1634 /*
1635 * Find who's first.
1636 */
Daniel Veillardf49be472004-02-17 11:48:18 +00001637 if (node1 == node2->prev)
1638 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001639 if (node1 == node2->next)
1640 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00001641 /*
1642 * Speedup using document order if availble.
1643 */
1644 if ((node1->type == XML_ELEMENT_NODE) &&
1645 (node2->type == XML_ELEMENT_NODE) &&
1646 (0 > (long) node1->content) &&
1647 (0 > (long) node2->content) &&
1648 (node1->doc == node2->doc)) {
1649 long l1, l2;
1650
1651 l1 = -((long) node1->content);
1652 l2 = -((long) node2->content);
1653 if (l1 < l2)
1654 return(1);
1655 if (l1 > l2)
1656 return(-1);
1657 }
1658
Owen Taylor3473f882001-02-23 17:55:21 +00001659 for (cur = node1->next;cur != NULL;cur = cur->next)
1660 if (cur == node2)
1661 return(1);
1662 return(-1); /* assume there is no sibling list corruption */
1663}
1664
1665/**
1666 * xmlXPathNodeSetSort:
1667 * @set: the node set
1668 *
1669 * Sort the node set in document order
1670 */
1671void
1672xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001673 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001674 xmlNodePtr tmp;
1675
1676 if (set == NULL)
1677 return;
1678
1679 /* Use Shell's sort to sort the node-set */
1680 len = set->nodeNr;
1681 for (incr = len / 2; incr > 0; incr /= 2) {
1682 for (i = incr; i < len; i++) {
1683 j = i - incr;
1684 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001685 if (xmlXPathCmpNodes(set->nodeTab[j],
1686 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001687 tmp = set->nodeTab[j];
1688 set->nodeTab[j] = set->nodeTab[j + incr];
1689 set->nodeTab[j + incr] = tmp;
1690 j -= incr;
1691 } else
1692 break;
1693 }
1694 }
1695 }
1696}
1697
1698#define XML_NODESET_DEFAULT 10
1699/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001700 * xmlXPathNodeSetDupNs:
1701 * @node: the parent node of the namespace XPath node
1702 * @ns: the libxml namespace declaration node.
1703 *
1704 * Namespace node in libxml don't match the XPath semantic. In a node set
1705 * the namespace nodes are duplicated and the next pointer is set to the
1706 * parent node in the XPath semantic.
1707 *
1708 * Returns the newly created object.
1709 */
1710static xmlNodePtr
1711xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1712 xmlNsPtr cur;
1713
1714 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1715 return(NULL);
1716 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1717 return((xmlNodePtr) ns);
1718
1719 /*
1720 * Allocate a new Namespace and fill the fields.
1721 */
1722 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1723 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001724 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001725 return(NULL);
1726 }
1727 memset(cur, 0, sizeof(xmlNs));
1728 cur->type = XML_NAMESPACE_DECL;
1729 if (ns->href != NULL)
1730 cur->href = xmlStrdup(ns->href);
1731 if (ns->prefix != NULL)
1732 cur->prefix = xmlStrdup(ns->prefix);
1733 cur->next = (xmlNsPtr) node;
1734 return((xmlNodePtr) cur);
1735}
1736
1737/**
1738 * xmlXPathNodeSetFreeNs:
1739 * @ns: the XPath namespace node found in a nodeset.
1740 *
William M. Brack08171912003-12-29 02:52:11 +00001741 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001742 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00001743 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001744 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001745void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001746xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1747 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1748 return;
1749
1750 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1751 if (ns->href != NULL)
1752 xmlFree((xmlChar *)ns->href);
1753 if (ns->prefix != NULL)
1754 xmlFree((xmlChar *)ns->prefix);
1755 xmlFree(ns);
1756 }
1757}
1758
1759/**
Owen Taylor3473f882001-02-23 17:55:21 +00001760 * xmlXPathNodeSetCreate:
1761 * @val: an initial xmlNodePtr, or NULL
1762 *
1763 * Create a new xmlNodeSetPtr of type double and of value @val
1764 *
1765 * Returns the newly created object.
1766 */
1767xmlNodeSetPtr
1768xmlXPathNodeSetCreate(xmlNodePtr val) {
1769 xmlNodeSetPtr ret;
1770
1771 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1772 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001773 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001774 return(NULL);
1775 }
1776 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1777 if (val != NULL) {
1778 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1779 sizeof(xmlNodePtr));
1780 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001781 xmlXPathErrMemory(NULL, "creating nodeset\n");
1782 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001783 return(NULL);
1784 }
1785 memset(ret->nodeTab, 0 ,
1786 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1787 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001788 if (val->type == XML_NAMESPACE_DECL) {
1789 xmlNsPtr ns = (xmlNsPtr) val;
1790
1791 ret->nodeTab[ret->nodeNr++] =
1792 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1793 } else
1794 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001795 }
1796 return(ret);
1797}
1798
1799/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001800 * xmlXPathNodeSetContains:
1801 * @cur: the node-set
1802 * @val: the node
1803 *
1804 * checks whether @cur contains @val
1805 *
1806 * Returns true (1) if @cur contains @val, false (0) otherwise
1807 */
1808int
1809xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1810 int i;
1811
Daniel Veillarda82b1822004-11-08 16:24:57 +00001812 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001813 if (val->type == XML_NAMESPACE_DECL) {
1814 for (i = 0; i < cur->nodeNr; i++) {
1815 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1816 xmlNsPtr ns1, ns2;
1817
1818 ns1 = (xmlNsPtr) val;
1819 ns2 = (xmlNsPtr) cur->nodeTab[i];
1820 if (ns1 == ns2)
1821 return(1);
1822 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1823 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1824 return(1);
1825 }
1826 }
1827 } else {
1828 for (i = 0; i < cur->nodeNr; i++) {
1829 if (cur->nodeTab[i] == val)
1830 return(1);
1831 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001832 }
1833 return(0);
1834}
1835
1836/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001837 * xmlXPathNodeSetAddNs:
1838 * @cur: the initial node set
1839 * @node: the hosting node
1840 * @ns: a the namespace node
1841 *
1842 * add a new namespace node to an existing NodeSet
1843 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001844void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001845xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1846 int i;
1847
Daniel Veillarda82b1822004-11-08 16:24:57 +00001848
1849 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
1850 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001851 (node->type != XML_ELEMENT_NODE))
1852 return;
1853
William M. Brack08171912003-12-29 02:52:11 +00001854 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001855 /*
William M. Brack08171912003-12-29 02:52:11 +00001856 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001857 */
1858 for (i = 0;i < cur->nodeNr;i++) {
1859 if ((cur->nodeTab[i] != NULL) &&
1860 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001861 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001862 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1863 return;
1864 }
1865
1866 /*
1867 * grow the nodeTab if needed
1868 */
1869 if (cur->nodeMax == 0) {
1870 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1871 sizeof(xmlNodePtr));
1872 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001873 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001874 return;
1875 }
1876 memset(cur->nodeTab, 0 ,
1877 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1878 cur->nodeMax = XML_NODESET_DEFAULT;
1879 } else if (cur->nodeNr == cur->nodeMax) {
1880 xmlNodePtr *temp;
1881
1882 cur->nodeMax *= 2;
1883 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1884 sizeof(xmlNodePtr));
1885 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001886 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001887 return;
1888 }
1889 cur->nodeTab = temp;
1890 }
1891 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1892}
1893
1894/**
Owen Taylor3473f882001-02-23 17:55:21 +00001895 * xmlXPathNodeSetAdd:
1896 * @cur: the initial node set
1897 * @val: a new xmlNodePtr
1898 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001899 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001900 */
1901void
1902xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1903 int i;
1904
Daniel Veillarda82b1822004-11-08 16:24:57 +00001905 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001906
Daniel Veillardef0b4502003-03-24 13:57:34 +00001907#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001908 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1909 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001910#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001911
William M. Brack08171912003-12-29 02:52:11 +00001912 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001913 /*
William M. Brack08171912003-12-29 02:52:11 +00001914 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00001915 */
1916 for (i = 0;i < cur->nodeNr;i++)
1917 if (cur->nodeTab[i] == val) return;
1918
1919 /*
1920 * grow the nodeTab if needed
1921 */
1922 if (cur->nodeMax == 0) {
1923 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1924 sizeof(xmlNodePtr));
1925 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001926 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001927 return;
1928 }
1929 memset(cur->nodeTab, 0 ,
1930 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1931 cur->nodeMax = XML_NODESET_DEFAULT;
1932 } else if (cur->nodeNr == cur->nodeMax) {
1933 xmlNodePtr *temp;
1934
1935 cur->nodeMax *= 2;
1936 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1937 sizeof(xmlNodePtr));
1938 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001939 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001940 return;
1941 }
1942 cur->nodeTab = temp;
1943 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001944 if (val->type == XML_NAMESPACE_DECL) {
1945 xmlNsPtr ns = (xmlNsPtr) val;
1946
1947 cur->nodeTab[cur->nodeNr++] =
1948 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1949 } else
1950 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001951}
1952
1953/**
1954 * xmlXPathNodeSetAddUnique:
1955 * @cur: the initial node set
1956 * @val: a new xmlNodePtr
1957 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001958 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001959 * when we are sure the node is not already in the set.
1960 */
1961void
1962xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00001963 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001964
Daniel Veillardef0b4502003-03-24 13:57:34 +00001965#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001966 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1967 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001968#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001969
William M. Brack08171912003-12-29 02:52:11 +00001970 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001971 /*
1972 * grow the nodeTab if needed
1973 */
1974 if (cur->nodeMax == 0) {
1975 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1976 sizeof(xmlNodePtr));
1977 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001978 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001979 return;
1980 }
1981 memset(cur->nodeTab, 0 ,
1982 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1983 cur->nodeMax = XML_NODESET_DEFAULT;
1984 } else if (cur->nodeNr == cur->nodeMax) {
1985 xmlNodePtr *temp;
1986
1987 cur->nodeMax *= 2;
1988 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1989 sizeof(xmlNodePtr));
1990 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001991 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001992 return;
1993 }
1994 cur->nodeTab = temp;
1995 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001996 if (val->type == XML_NAMESPACE_DECL) {
1997 xmlNsPtr ns = (xmlNsPtr) val;
1998
1999 cur->nodeTab[cur->nodeNr++] =
2000 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2001 } else
2002 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00002003}
2004
2005/**
2006 * xmlXPathNodeSetMerge:
2007 * @val1: the first NodeSet or NULL
2008 * @val2: the second NodeSet
2009 *
2010 * Merges two nodesets, all nodes from @val2 are added to @val1
2011 * if @val1 is NULL, a new set is created and copied from @val2
2012 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002013 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002014 */
2015xmlNodeSetPtr
2016xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002017 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00002018
2019 if (val2 == NULL) return(val1);
2020 if (val1 == NULL) {
2021 val1 = xmlXPathNodeSetCreate(NULL);
2022 }
2023
William M. Brack08171912003-12-29 02:52:11 +00002024 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002025 initNr = val1->nodeNr;
2026
2027 for (i = 0;i < val2->nodeNr;i++) {
2028 /*
William M. Brack08171912003-12-29 02:52:11 +00002029 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00002030 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002031 skip = 0;
2032 for (j = 0; j < initNr; j++) {
2033 if (val1->nodeTab[j] == val2->nodeTab[i]) {
2034 skip = 1;
2035 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002036 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
2037 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
2038 xmlNsPtr ns1, ns2;
2039 ns1 = (xmlNsPtr) val1->nodeTab[j];
2040 ns2 = (xmlNsPtr) val2->nodeTab[i];
2041 if ((ns1->next == ns2->next) &&
2042 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
2043 skip = 1;
2044 break;
2045 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002046 }
2047 }
2048 if (skip)
2049 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00002050
2051 /*
2052 * grow the nodeTab if needed
2053 */
2054 if (val1->nodeMax == 0) {
2055 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2056 sizeof(xmlNodePtr));
2057 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002058 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002059 return(NULL);
2060 }
2061 memset(val1->nodeTab, 0 ,
2062 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2063 val1->nodeMax = XML_NODESET_DEFAULT;
2064 } else if (val1->nodeNr == val1->nodeMax) {
2065 xmlNodePtr *temp;
2066
2067 val1->nodeMax *= 2;
2068 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2069 sizeof(xmlNodePtr));
2070 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002071 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002072 return(NULL);
2073 }
2074 val1->nodeTab = temp;
2075 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002076 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2077 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2078
2079 val1->nodeTab[val1->nodeNr++] =
2080 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2081 } else
2082 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002083 }
2084
2085 return(val1);
2086}
2087
2088/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002089 * xmlXPathNodeSetMergeUnique:
2090 * @val1: the first NodeSet or NULL
2091 * @val2: the second NodeSet
2092 *
2093 * Merges two nodesets, all nodes from @val2 are added to @val1
2094 * if @val1 is NULL, a new set is created and copied from @val2
2095 *
2096 * Returns @val1 once extended or NULL in case of error.
2097 */
2098static xmlNodeSetPtr
2099xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002100 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002101
2102 if (val2 == NULL) return(val1);
2103 if (val1 == NULL) {
2104 val1 = xmlXPathNodeSetCreate(NULL);
2105 }
2106
William M. Brack08171912003-12-29 02:52:11 +00002107 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002108
2109 for (i = 0;i < val2->nodeNr;i++) {
2110 /*
2111 * grow the nodeTab if needed
2112 */
2113 if (val1->nodeMax == 0) {
2114 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2115 sizeof(xmlNodePtr));
2116 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002117 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002118 return(NULL);
2119 }
2120 memset(val1->nodeTab, 0 ,
2121 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2122 val1->nodeMax = XML_NODESET_DEFAULT;
2123 } else if (val1->nodeNr == val1->nodeMax) {
2124 xmlNodePtr *temp;
2125
2126 val1->nodeMax *= 2;
2127 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2128 sizeof(xmlNodePtr));
2129 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002130 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002131 return(NULL);
2132 }
2133 val1->nodeTab = temp;
2134 }
2135 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2136 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2137
2138 val1->nodeTab[val1->nodeNr++] =
2139 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2140 } else
2141 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2142 }
2143
2144 return(val1);
2145}
2146
2147/**
Owen Taylor3473f882001-02-23 17:55:21 +00002148 * xmlXPathNodeSetDel:
2149 * @cur: the initial node set
2150 * @val: an xmlNodePtr
2151 *
2152 * Removes an xmlNodePtr from an existing NodeSet
2153 */
2154void
2155xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2156 int i;
2157
2158 if (cur == NULL) return;
2159 if (val == NULL) return;
2160
2161 /*
William M. Brack08171912003-12-29 02:52:11 +00002162 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002163 */
2164 for (i = 0;i < cur->nodeNr;i++)
2165 if (cur->nodeTab[i] == val) break;
2166
William M. Brack08171912003-12-29 02:52:11 +00002167 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002168#ifdef DEBUG
2169 xmlGenericError(xmlGenericErrorContext,
2170 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2171 val->name);
2172#endif
2173 return;
2174 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002175 if ((cur->nodeTab[i] != NULL) &&
2176 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2177 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002178 cur->nodeNr--;
2179 for (;i < cur->nodeNr;i++)
2180 cur->nodeTab[i] = cur->nodeTab[i + 1];
2181 cur->nodeTab[cur->nodeNr] = NULL;
2182}
2183
2184/**
2185 * xmlXPathNodeSetRemove:
2186 * @cur: the initial node set
2187 * @val: the index to remove
2188 *
2189 * Removes an entry from an existing NodeSet list.
2190 */
2191void
2192xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2193 if (cur == NULL) return;
2194 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002195 if ((cur->nodeTab[val] != NULL) &&
2196 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2197 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002198 cur->nodeNr--;
2199 for (;val < cur->nodeNr;val++)
2200 cur->nodeTab[val] = cur->nodeTab[val + 1];
2201 cur->nodeTab[cur->nodeNr] = NULL;
2202}
2203
2204/**
2205 * xmlXPathFreeNodeSet:
2206 * @obj: the xmlNodeSetPtr to free
2207 *
2208 * Free the NodeSet compound (not the actual nodes !).
2209 */
2210void
2211xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2212 if (obj == NULL) return;
2213 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002214 int i;
2215
William M. Brack08171912003-12-29 02:52:11 +00002216 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002217 for (i = 0;i < obj->nodeNr;i++)
2218 if ((obj->nodeTab[i] != NULL) &&
2219 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2220 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002221 xmlFree(obj->nodeTab);
2222 }
Owen Taylor3473f882001-02-23 17:55:21 +00002223 xmlFree(obj);
2224}
2225
2226/**
2227 * xmlXPathFreeValueTree:
2228 * @obj: the xmlNodeSetPtr to free
2229 *
2230 * Free the NodeSet compound and the actual tree, this is different
2231 * from xmlXPathFreeNodeSet()
2232 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002233static void
Owen Taylor3473f882001-02-23 17:55:21 +00002234xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2235 int i;
2236
2237 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002238
2239 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002240 for (i = 0;i < obj->nodeNr;i++) {
2241 if (obj->nodeTab[i] != NULL) {
2242 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2243 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2244 } else {
2245 xmlFreeNodeList(obj->nodeTab[i]);
2246 }
2247 }
2248 }
Owen Taylor3473f882001-02-23 17:55:21 +00002249 xmlFree(obj->nodeTab);
2250 }
Owen Taylor3473f882001-02-23 17:55:21 +00002251 xmlFree(obj);
2252}
2253
2254#if defined(DEBUG) || defined(DEBUG_STEP)
2255/**
2256 * xmlGenericErrorContextNodeSet:
2257 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002258 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002259 *
2260 * Quick display of a NodeSet
2261 */
2262void
2263xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2264 int i;
2265
2266 if (output == NULL) output = xmlGenericErrorContext;
2267 if (obj == NULL) {
2268 fprintf(output, "NodeSet == NULL !\n");
2269 return;
2270 }
2271 if (obj->nodeNr == 0) {
2272 fprintf(output, "NodeSet is empty\n");
2273 return;
2274 }
2275 if (obj->nodeTab == NULL) {
2276 fprintf(output, " nodeTab == NULL !\n");
2277 return;
2278 }
2279 for (i = 0; i < obj->nodeNr; i++) {
2280 if (obj->nodeTab[i] == NULL) {
2281 fprintf(output, " NULL !\n");
2282 return;
2283 }
2284 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2285 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2286 fprintf(output, " /");
2287 else if (obj->nodeTab[i]->name == NULL)
2288 fprintf(output, " noname!");
2289 else fprintf(output, " %s", obj->nodeTab[i]->name);
2290 }
2291 fprintf(output, "\n");
2292}
2293#endif
2294
2295/**
2296 * xmlXPathNewNodeSet:
2297 * @val: the NodePtr value
2298 *
2299 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2300 * it with the single Node @val
2301 *
2302 * Returns the newly created object.
2303 */
2304xmlXPathObjectPtr
2305xmlXPathNewNodeSet(xmlNodePtr val) {
2306 xmlXPathObjectPtr ret;
2307
2308 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2309 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002310 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002311 return(NULL);
2312 }
2313 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2314 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002315 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002316 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002317 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002318 return(ret);
2319}
2320
2321/**
2322 * xmlXPathNewValueTree:
2323 * @val: the NodePtr value
2324 *
2325 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2326 * it with the tree root @val
2327 *
2328 * Returns the newly created object.
2329 */
2330xmlXPathObjectPtr
2331xmlXPathNewValueTree(xmlNodePtr val) {
2332 xmlXPathObjectPtr ret;
2333
2334 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2335 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002336 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002337 return(NULL);
2338 }
2339 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2340 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002341 ret->boolval = 1;
2342 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002343 ret->nodesetval = xmlXPathNodeSetCreate(val);
2344 return(ret);
2345}
2346
2347/**
2348 * xmlXPathNewNodeSetList:
2349 * @val: an existing NodeSet
2350 *
2351 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2352 * it with the Nodeset @val
2353 *
2354 * Returns the newly created object.
2355 */
2356xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002357xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2358{
Owen Taylor3473f882001-02-23 17:55:21 +00002359 xmlXPathObjectPtr ret;
2360 int i;
2361
2362 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002363 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002364 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002365 ret = xmlXPathNewNodeSet(NULL);
2366 else {
2367 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2368 for (i = 1; i < val->nodeNr; ++i)
2369 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2370 }
Owen Taylor3473f882001-02-23 17:55:21 +00002371
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002372 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002373}
2374
2375/**
2376 * xmlXPathWrapNodeSet:
2377 * @val: the NodePtr value
2378 *
2379 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2380 *
2381 * Returns the newly created object.
2382 */
2383xmlXPathObjectPtr
2384xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2385 xmlXPathObjectPtr ret;
2386
2387 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2388 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002389 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002390 return(NULL);
2391 }
2392 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2393 ret->type = XPATH_NODESET;
2394 ret->nodesetval = val;
2395 return(ret);
2396}
2397
2398/**
2399 * xmlXPathFreeNodeSetList:
2400 * @obj: an existing NodeSetList object
2401 *
2402 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2403 * the list contrary to xmlXPathFreeObject().
2404 */
2405void
2406xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2407 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002408 xmlFree(obj);
2409}
2410
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002411/**
2412 * xmlXPathDifference:
2413 * @nodes1: a node-set
2414 * @nodes2: a node-set
2415 *
2416 * Implements the EXSLT - Sets difference() function:
2417 * node-set set:difference (node-set, node-set)
2418 *
2419 * Returns the difference between the two node sets, or nodes1 if
2420 * nodes2 is empty
2421 */
2422xmlNodeSetPtr
2423xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2424 xmlNodeSetPtr ret;
2425 int i, l1;
2426 xmlNodePtr cur;
2427
2428 if (xmlXPathNodeSetIsEmpty(nodes2))
2429 return(nodes1);
2430
2431 ret = xmlXPathNodeSetCreate(NULL);
2432 if (xmlXPathNodeSetIsEmpty(nodes1))
2433 return(ret);
2434
2435 l1 = xmlXPathNodeSetGetLength(nodes1);
2436
2437 for (i = 0; i < l1; i++) {
2438 cur = xmlXPathNodeSetItem(nodes1, i);
2439 if (!xmlXPathNodeSetContains(nodes2, cur))
2440 xmlXPathNodeSetAddUnique(ret, cur);
2441 }
2442 return(ret);
2443}
2444
2445/**
2446 * xmlXPathIntersection:
2447 * @nodes1: a node-set
2448 * @nodes2: a node-set
2449 *
2450 * Implements the EXSLT - Sets intersection() function:
2451 * node-set set:intersection (node-set, node-set)
2452 *
2453 * Returns a node set comprising the nodes that are within both the
2454 * node sets passed as arguments
2455 */
2456xmlNodeSetPtr
2457xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2458 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2459 int i, l1;
2460 xmlNodePtr cur;
2461
2462 if (xmlXPathNodeSetIsEmpty(nodes1))
2463 return(ret);
2464 if (xmlXPathNodeSetIsEmpty(nodes2))
2465 return(ret);
2466
2467 l1 = xmlXPathNodeSetGetLength(nodes1);
2468
2469 for (i = 0; i < l1; i++) {
2470 cur = xmlXPathNodeSetItem(nodes1, i);
2471 if (xmlXPathNodeSetContains(nodes2, cur))
2472 xmlXPathNodeSetAddUnique(ret, cur);
2473 }
2474 return(ret);
2475}
2476
2477/**
2478 * xmlXPathDistinctSorted:
2479 * @nodes: a node-set, sorted by document order
2480 *
2481 * Implements the EXSLT - Sets distinct() function:
2482 * node-set set:distinct (node-set)
2483 *
2484 * Returns a subset of the nodes contained in @nodes, or @nodes if
2485 * it is empty
2486 */
2487xmlNodeSetPtr
2488xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2489 xmlNodeSetPtr ret;
2490 xmlHashTablePtr hash;
2491 int i, l;
2492 xmlChar * strval;
2493 xmlNodePtr cur;
2494
2495 if (xmlXPathNodeSetIsEmpty(nodes))
2496 return(nodes);
2497
2498 ret = xmlXPathNodeSetCreate(NULL);
2499 l = xmlXPathNodeSetGetLength(nodes);
2500 hash = xmlHashCreate (l);
2501 for (i = 0; i < l; i++) {
2502 cur = xmlXPathNodeSetItem(nodes, i);
2503 strval = xmlXPathCastNodeToString(cur);
2504 if (xmlHashLookup(hash, strval) == NULL) {
2505 xmlHashAddEntry(hash, strval, strval);
2506 xmlXPathNodeSetAddUnique(ret, cur);
2507 } else {
2508 xmlFree(strval);
2509 }
2510 }
2511 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2512 return(ret);
2513}
2514
2515/**
2516 * xmlXPathDistinct:
2517 * @nodes: a node-set
2518 *
2519 * Implements the EXSLT - Sets distinct() function:
2520 * node-set set:distinct (node-set)
2521 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2522 * is called with the sorted node-set
2523 *
2524 * Returns a subset of the nodes contained in @nodes, or @nodes if
2525 * it is empty
2526 */
2527xmlNodeSetPtr
2528xmlXPathDistinct (xmlNodeSetPtr nodes) {
2529 if (xmlXPathNodeSetIsEmpty(nodes))
2530 return(nodes);
2531
2532 xmlXPathNodeSetSort(nodes);
2533 return(xmlXPathDistinctSorted(nodes));
2534}
2535
2536/**
2537 * xmlXPathHasSameNodes:
2538 * @nodes1: a node-set
2539 * @nodes2: a node-set
2540 *
2541 * Implements the EXSLT - Sets has-same-nodes function:
2542 * boolean set:has-same-node(node-set, node-set)
2543 *
2544 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2545 * otherwise
2546 */
2547int
2548xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2549 int i, l;
2550 xmlNodePtr cur;
2551
2552 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2553 xmlXPathNodeSetIsEmpty(nodes2))
2554 return(0);
2555
2556 l = xmlXPathNodeSetGetLength(nodes1);
2557 for (i = 0; i < l; i++) {
2558 cur = xmlXPathNodeSetItem(nodes1, i);
2559 if (xmlXPathNodeSetContains(nodes2, cur))
2560 return(1);
2561 }
2562 return(0);
2563}
2564
2565/**
2566 * xmlXPathNodeLeadingSorted:
2567 * @nodes: a node-set, sorted by document order
2568 * @node: a node
2569 *
2570 * Implements the EXSLT - Sets leading() function:
2571 * node-set set:leading (node-set, node-set)
2572 *
2573 * Returns the nodes in @nodes that precede @node in document order,
2574 * @nodes if @node is NULL or an empty node-set if @nodes
2575 * doesn't contain @node
2576 */
2577xmlNodeSetPtr
2578xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2579 int i, l;
2580 xmlNodePtr cur;
2581 xmlNodeSetPtr ret;
2582
2583 if (node == NULL)
2584 return(nodes);
2585
2586 ret = xmlXPathNodeSetCreate(NULL);
2587 if (xmlXPathNodeSetIsEmpty(nodes) ||
2588 (!xmlXPathNodeSetContains(nodes, node)))
2589 return(ret);
2590
2591 l = xmlXPathNodeSetGetLength(nodes);
2592 for (i = 0; i < l; i++) {
2593 cur = xmlXPathNodeSetItem(nodes, i);
2594 if (cur == node)
2595 break;
2596 xmlXPathNodeSetAddUnique(ret, cur);
2597 }
2598 return(ret);
2599}
2600
2601/**
2602 * xmlXPathNodeLeading:
2603 * @nodes: a node-set
2604 * @node: a node
2605 *
2606 * Implements the EXSLT - Sets leading() function:
2607 * node-set set:leading (node-set, node-set)
2608 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2609 * is called.
2610 *
2611 * Returns the nodes in @nodes that precede @node in document order,
2612 * @nodes if @node is NULL or an empty node-set if @nodes
2613 * doesn't contain @node
2614 */
2615xmlNodeSetPtr
2616xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2617 xmlXPathNodeSetSort(nodes);
2618 return(xmlXPathNodeLeadingSorted(nodes, node));
2619}
2620
2621/**
2622 * xmlXPathLeadingSorted:
2623 * @nodes1: a node-set, sorted by document order
2624 * @nodes2: a node-set, sorted by document order
2625 *
2626 * Implements the EXSLT - Sets leading() function:
2627 * node-set set:leading (node-set, node-set)
2628 *
2629 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2630 * in document order, @nodes1 if @nodes2 is NULL or empty or
2631 * an empty node-set if @nodes1 doesn't contain @nodes2
2632 */
2633xmlNodeSetPtr
2634xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2635 if (xmlXPathNodeSetIsEmpty(nodes2))
2636 return(nodes1);
2637 return(xmlXPathNodeLeadingSorted(nodes1,
2638 xmlXPathNodeSetItem(nodes2, 1)));
2639}
2640
2641/**
2642 * xmlXPathLeading:
2643 * @nodes1: a node-set
2644 * @nodes2: a node-set
2645 *
2646 * Implements the EXSLT - Sets leading() function:
2647 * node-set set:leading (node-set, node-set)
2648 * @nodes1 and @nodes2 are sorted by document order, then
2649 * #exslSetsLeadingSorted is called.
2650 *
2651 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2652 * in document order, @nodes1 if @nodes2 is NULL or empty or
2653 * an empty node-set if @nodes1 doesn't contain @nodes2
2654 */
2655xmlNodeSetPtr
2656xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2657 if (xmlXPathNodeSetIsEmpty(nodes2))
2658 return(nodes1);
2659 if (xmlXPathNodeSetIsEmpty(nodes1))
2660 return(xmlXPathNodeSetCreate(NULL));
2661 xmlXPathNodeSetSort(nodes1);
2662 xmlXPathNodeSetSort(nodes2);
2663 return(xmlXPathNodeLeadingSorted(nodes1,
2664 xmlXPathNodeSetItem(nodes2, 1)));
2665}
2666
2667/**
2668 * xmlXPathNodeTrailingSorted:
2669 * @nodes: a node-set, sorted by document order
2670 * @node: a node
2671 *
2672 * Implements the EXSLT - Sets trailing() function:
2673 * node-set set:trailing (node-set, node-set)
2674 *
2675 * Returns the nodes in @nodes that follow @node in document order,
2676 * @nodes if @node is NULL or an empty node-set if @nodes
2677 * doesn't contain @node
2678 */
2679xmlNodeSetPtr
2680xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2681 int i, l;
2682 xmlNodePtr cur;
2683 xmlNodeSetPtr ret;
2684
2685 if (node == NULL)
2686 return(nodes);
2687
2688 ret = xmlXPathNodeSetCreate(NULL);
2689 if (xmlXPathNodeSetIsEmpty(nodes) ||
2690 (!xmlXPathNodeSetContains(nodes, node)))
2691 return(ret);
2692
2693 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002694 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002695 cur = xmlXPathNodeSetItem(nodes, i);
2696 if (cur == node)
2697 break;
2698 xmlXPathNodeSetAddUnique(ret, cur);
2699 }
2700 return(ret);
2701}
2702
2703/**
2704 * xmlXPathNodeTrailing:
2705 * @nodes: a node-set
2706 * @node: a node
2707 *
2708 * Implements the EXSLT - Sets trailing() function:
2709 * node-set set:trailing (node-set, node-set)
2710 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2711 * is called.
2712 *
2713 * Returns the nodes in @nodes that follow @node in document order,
2714 * @nodes if @node is NULL or an empty node-set if @nodes
2715 * doesn't contain @node
2716 */
2717xmlNodeSetPtr
2718xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2719 xmlXPathNodeSetSort(nodes);
2720 return(xmlXPathNodeTrailingSorted(nodes, node));
2721}
2722
2723/**
2724 * xmlXPathTrailingSorted:
2725 * @nodes1: a node-set, sorted by document order
2726 * @nodes2: a node-set, sorted by document order
2727 *
2728 * Implements the EXSLT - Sets trailing() function:
2729 * node-set set:trailing (node-set, node-set)
2730 *
2731 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2732 * in document order, @nodes1 if @nodes2 is NULL or empty or
2733 * an empty node-set if @nodes1 doesn't contain @nodes2
2734 */
2735xmlNodeSetPtr
2736xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2737 if (xmlXPathNodeSetIsEmpty(nodes2))
2738 return(nodes1);
2739 return(xmlXPathNodeTrailingSorted(nodes1,
2740 xmlXPathNodeSetItem(nodes2, 0)));
2741}
2742
2743/**
2744 * xmlXPathTrailing:
2745 * @nodes1: a node-set
2746 * @nodes2: a node-set
2747 *
2748 * Implements the EXSLT - Sets trailing() function:
2749 * node-set set:trailing (node-set, node-set)
2750 * @nodes1 and @nodes2 are sorted by document order, then
2751 * #xmlXPathTrailingSorted is called.
2752 *
2753 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2754 * in document order, @nodes1 if @nodes2 is NULL or empty or
2755 * an empty node-set if @nodes1 doesn't contain @nodes2
2756 */
2757xmlNodeSetPtr
2758xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2759 if (xmlXPathNodeSetIsEmpty(nodes2))
2760 return(nodes1);
2761 if (xmlXPathNodeSetIsEmpty(nodes1))
2762 return(xmlXPathNodeSetCreate(NULL));
2763 xmlXPathNodeSetSort(nodes1);
2764 xmlXPathNodeSetSort(nodes2);
2765 return(xmlXPathNodeTrailingSorted(nodes1,
2766 xmlXPathNodeSetItem(nodes2, 0)));
2767}
2768
Owen Taylor3473f882001-02-23 17:55:21 +00002769/************************************************************************
2770 * *
2771 * Routines to handle extra functions *
2772 * *
2773 ************************************************************************/
2774
2775/**
2776 * xmlXPathRegisterFunc:
2777 * @ctxt: the XPath context
2778 * @name: the function name
2779 * @f: the function implementation or NULL
2780 *
2781 * Register a new function. If @f is NULL it unregisters the function
2782 *
2783 * Returns 0 in case of success, -1 in case of error
2784 */
2785int
2786xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2787 xmlXPathFunction f) {
2788 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2789}
2790
2791/**
2792 * xmlXPathRegisterFuncNS:
2793 * @ctxt: the XPath context
2794 * @name: the function name
2795 * @ns_uri: the function namespace URI
2796 * @f: the function implementation or NULL
2797 *
2798 * Register a new function. If @f is NULL it unregisters the function
2799 *
2800 * Returns 0 in case of success, -1 in case of error
2801 */
2802int
2803xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2804 const xmlChar *ns_uri, xmlXPathFunction f) {
2805 if (ctxt == NULL)
2806 return(-1);
2807 if (name == NULL)
2808 return(-1);
2809
2810 if (ctxt->funcHash == NULL)
2811 ctxt->funcHash = xmlHashCreate(0);
2812 if (ctxt->funcHash == NULL)
2813 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002814 if (f == NULL)
2815 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
Owen Taylor3473f882001-02-23 17:55:21 +00002816 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2817}
2818
2819/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002820 * xmlXPathRegisterFuncLookup:
2821 * @ctxt: the XPath context
2822 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002823 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002824 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002825 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002826 */
2827void
2828xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2829 xmlXPathFuncLookupFunc f,
2830 void *funcCtxt) {
2831 if (ctxt == NULL)
2832 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002833 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002834 ctxt->funcLookupData = funcCtxt;
2835}
2836
2837/**
Owen Taylor3473f882001-02-23 17:55:21 +00002838 * xmlXPathFunctionLookup:
2839 * @ctxt: the XPath context
2840 * @name: the function name
2841 *
2842 * Search in the Function array of the context for the given
2843 * function.
2844 *
2845 * Returns the xmlXPathFunction or NULL if not found
2846 */
2847xmlXPathFunction
2848xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002849 if (ctxt == NULL)
2850 return (NULL);
2851
2852 if (ctxt->funcLookupFunc != NULL) {
2853 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002854 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002855
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002856 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002857 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002858 if (ret != NULL)
2859 return(ret);
2860 }
Owen Taylor3473f882001-02-23 17:55:21 +00002861 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2862}
2863
2864/**
2865 * xmlXPathFunctionLookupNS:
2866 * @ctxt: the XPath context
2867 * @name: the function name
2868 * @ns_uri: the function namespace URI
2869 *
2870 * Search in the Function array of the context for the given
2871 * function.
2872 *
2873 * Returns the xmlXPathFunction or NULL if not found
2874 */
2875xmlXPathFunction
2876xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2877 const xmlChar *ns_uri) {
2878 if (ctxt == NULL)
2879 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002880 if (name == NULL)
2881 return(NULL);
2882
Thomas Broyerba4ad322001-07-26 16:55:21 +00002883 if (ctxt->funcLookupFunc != NULL) {
2884 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002885 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002886
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002887 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002888 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002889 if (ret != NULL)
2890 return(ret);
2891 }
2892
2893 if (ctxt->funcHash == NULL)
2894 return(NULL);
2895
Owen Taylor3473f882001-02-23 17:55:21 +00002896 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2897}
2898
2899/**
2900 * xmlXPathRegisteredFuncsCleanup:
2901 * @ctxt: the XPath context
2902 *
2903 * Cleanup the XPath context data associated to registered functions
2904 */
2905void
2906xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2907 if (ctxt == NULL)
2908 return;
2909
2910 xmlHashFree(ctxt->funcHash, NULL);
2911 ctxt->funcHash = NULL;
2912}
2913
2914/************************************************************************
2915 * *
William M. Brack08171912003-12-29 02:52:11 +00002916 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00002917 * *
2918 ************************************************************************/
2919
2920/**
2921 * xmlXPathRegisterVariable:
2922 * @ctxt: the XPath context
2923 * @name: the variable name
2924 * @value: the variable value or NULL
2925 *
2926 * Register a new variable value. If @value is NULL it unregisters
2927 * the variable
2928 *
2929 * Returns 0 in case of success, -1 in case of error
2930 */
2931int
2932xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2933 xmlXPathObjectPtr value) {
2934 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2935}
2936
2937/**
2938 * xmlXPathRegisterVariableNS:
2939 * @ctxt: the XPath context
2940 * @name: the variable name
2941 * @ns_uri: the variable namespace URI
2942 * @value: the variable value or NULL
2943 *
2944 * Register a new variable value. If @value is NULL it unregisters
2945 * the variable
2946 *
2947 * Returns 0 in case of success, -1 in case of error
2948 */
2949int
2950xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2951 const xmlChar *ns_uri,
2952 xmlXPathObjectPtr value) {
2953 if (ctxt == NULL)
2954 return(-1);
2955 if (name == NULL)
2956 return(-1);
2957
2958 if (ctxt->varHash == NULL)
2959 ctxt->varHash = xmlHashCreate(0);
2960 if (ctxt->varHash == NULL)
2961 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002962 if (value == NULL)
2963 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2964 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002965 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2966 (void *) value,
2967 (xmlHashDeallocator)xmlXPathFreeObject));
2968}
2969
2970/**
2971 * xmlXPathRegisterVariableLookup:
2972 * @ctxt: the XPath context
2973 * @f: the lookup function
2974 * @data: the lookup data
2975 *
2976 * register an external mechanism to do variable lookup
2977 */
2978void
2979xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2980 xmlXPathVariableLookupFunc f, void *data) {
2981 if (ctxt == NULL)
2982 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002983 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00002984 ctxt->varLookupData = data;
2985}
2986
2987/**
2988 * xmlXPathVariableLookup:
2989 * @ctxt: the XPath context
2990 * @name: the variable name
2991 *
2992 * Search in the Variable array of the context for the given
2993 * variable value.
2994 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002995 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002996 */
2997xmlXPathObjectPtr
2998xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2999 if (ctxt == NULL)
3000 return(NULL);
3001
3002 if (ctxt->varLookupFunc != NULL) {
3003 xmlXPathObjectPtr ret;
3004
3005 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3006 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00003007 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003008 }
3009 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3010}
3011
3012/**
3013 * xmlXPathVariableLookupNS:
3014 * @ctxt: the XPath context
3015 * @name: the variable name
3016 * @ns_uri: the variable namespace URI
3017 *
3018 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00003019 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00003020 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003021 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003022 */
3023xmlXPathObjectPtr
3024xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3025 const xmlChar *ns_uri) {
3026 if (ctxt == NULL)
3027 return(NULL);
3028
3029 if (ctxt->varLookupFunc != NULL) {
3030 xmlXPathObjectPtr ret;
3031
3032 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3033 (ctxt->varLookupData, name, ns_uri);
3034 if (ret != NULL) return(ret);
3035 }
3036
3037 if (ctxt->varHash == NULL)
3038 return(NULL);
3039 if (name == NULL)
3040 return(NULL);
3041
Daniel Veillard8c357d52001-07-03 23:43:33 +00003042 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3043 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00003044}
3045
3046/**
3047 * xmlXPathRegisteredVariablesCleanup:
3048 * @ctxt: the XPath context
3049 *
3050 * Cleanup the XPath context data associated to registered variables
3051 */
3052void
3053xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3054 if (ctxt == NULL)
3055 return;
3056
Daniel Veillard76d66f42001-05-16 21:05:17 +00003057 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00003058 ctxt->varHash = NULL;
3059}
3060
3061/**
3062 * xmlXPathRegisterNs:
3063 * @ctxt: the XPath context
3064 * @prefix: the namespace prefix
3065 * @ns_uri: the namespace name
3066 *
3067 * Register a new namespace. If @ns_uri is NULL it unregisters
3068 * the namespace
3069 *
3070 * Returns 0 in case of success, -1 in case of error
3071 */
3072int
3073xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3074 const xmlChar *ns_uri) {
3075 if (ctxt == NULL)
3076 return(-1);
3077 if (prefix == NULL)
3078 return(-1);
3079
3080 if (ctxt->nsHash == NULL)
3081 ctxt->nsHash = xmlHashCreate(10);
3082 if (ctxt->nsHash == NULL)
3083 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003084 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003085 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003086 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003087 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003088 (xmlHashDeallocator)xmlFree));
3089}
3090
3091/**
3092 * xmlXPathNsLookup:
3093 * @ctxt: the XPath context
3094 * @prefix: the namespace prefix value
3095 *
3096 * Search in the namespace declaration array of the context for the given
3097 * namespace name associated to the given prefix
3098 *
3099 * Returns the value or NULL if not found
3100 */
3101const xmlChar *
3102xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3103 if (ctxt == NULL)
3104 return(NULL);
3105 if (prefix == NULL)
3106 return(NULL);
3107
3108#ifdef XML_XML_NAMESPACE
3109 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3110 return(XML_XML_NAMESPACE);
3111#endif
3112
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003113 if (ctxt->namespaces != NULL) {
3114 int i;
3115
3116 for (i = 0;i < ctxt->nsNr;i++) {
3117 if ((ctxt->namespaces[i] != NULL) &&
3118 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3119 return(ctxt->namespaces[i]->href);
3120 }
3121 }
Owen Taylor3473f882001-02-23 17:55:21 +00003122
3123 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3124}
3125
3126/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003127 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003128 * @ctxt: the XPath context
3129 *
3130 * Cleanup the XPath context data associated to registered variables
3131 */
3132void
3133xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3134 if (ctxt == NULL)
3135 return;
3136
Daniel Veillard42766c02002-08-22 20:52:17 +00003137 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003138 ctxt->nsHash = NULL;
3139}
3140
3141/************************************************************************
3142 * *
3143 * Routines to handle Values *
3144 * *
3145 ************************************************************************/
3146
William M. Brack08171912003-12-29 02:52:11 +00003147/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003148
3149/**
3150 * xmlXPathNewFloat:
3151 * @val: the double value
3152 *
3153 * Create a new xmlXPathObjectPtr of type double and of value @val
3154 *
3155 * Returns the newly created object.
3156 */
3157xmlXPathObjectPtr
3158xmlXPathNewFloat(double val) {
3159 xmlXPathObjectPtr ret;
3160
3161 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3162 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003163 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003164 return(NULL);
3165 }
3166 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3167 ret->type = XPATH_NUMBER;
3168 ret->floatval = val;
3169 return(ret);
3170}
3171
3172/**
3173 * xmlXPathNewBoolean:
3174 * @val: the boolean value
3175 *
3176 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3177 *
3178 * Returns the newly created object.
3179 */
3180xmlXPathObjectPtr
3181xmlXPathNewBoolean(int val) {
3182 xmlXPathObjectPtr ret;
3183
3184 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3185 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003186 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003187 return(NULL);
3188 }
3189 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3190 ret->type = XPATH_BOOLEAN;
3191 ret->boolval = (val != 0);
3192 return(ret);
3193}
3194
3195/**
3196 * xmlXPathNewString:
3197 * @val: the xmlChar * value
3198 *
3199 * Create a new xmlXPathObjectPtr of type string and of value @val
3200 *
3201 * Returns the newly created object.
3202 */
3203xmlXPathObjectPtr
3204xmlXPathNewString(const xmlChar *val) {
3205 xmlXPathObjectPtr ret;
3206
3207 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3208 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003209 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003210 return(NULL);
3211 }
3212 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3213 ret->type = XPATH_STRING;
3214 if (val != NULL)
3215 ret->stringval = xmlStrdup(val);
3216 else
3217 ret->stringval = xmlStrdup((const xmlChar *)"");
3218 return(ret);
3219}
3220
3221/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003222 * xmlXPathWrapString:
3223 * @val: the xmlChar * value
3224 *
3225 * Wraps the @val string into an XPath object.
3226 *
3227 * Returns the newly created object.
3228 */
3229xmlXPathObjectPtr
3230xmlXPathWrapString (xmlChar *val) {
3231 xmlXPathObjectPtr ret;
3232
3233 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3234 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003235 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003236 return(NULL);
3237 }
3238 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3239 ret->type = XPATH_STRING;
3240 ret->stringval = val;
3241 return(ret);
3242}
3243
3244/**
Owen Taylor3473f882001-02-23 17:55:21 +00003245 * xmlXPathNewCString:
3246 * @val: the char * value
3247 *
3248 * Create a new xmlXPathObjectPtr of type string and of value @val
3249 *
3250 * Returns the newly created object.
3251 */
3252xmlXPathObjectPtr
3253xmlXPathNewCString(const char *val) {
3254 xmlXPathObjectPtr ret;
3255
3256 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3257 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003258 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003259 return(NULL);
3260 }
3261 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3262 ret->type = XPATH_STRING;
3263 ret->stringval = xmlStrdup(BAD_CAST val);
3264 return(ret);
3265}
3266
3267/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003268 * xmlXPathWrapCString:
3269 * @val: the char * value
3270 *
3271 * Wraps a string into an XPath object.
3272 *
3273 * Returns the newly created object.
3274 */
3275xmlXPathObjectPtr
3276xmlXPathWrapCString (char * val) {
3277 return(xmlXPathWrapString((xmlChar *)(val)));
3278}
3279
3280/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003281 * xmlXPathWrapExternal:
3282 * @val: the user data
3283 *
3284 * Wraps the @val data into an XPath object.
3285 *
3286 * Returns the newly created object.
3287 */
3288xmlXPathObjectPtr
3289xmlXPathWrapExternal (void *val) {
3290 xmlXPathObjectPtr ret;
3291
3292 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3293 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003294 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003295 return(NULL);
3296 }
3297 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3298 ret->type = XPATH_USERS;
3299 ret->user = val;
3300 return(ret);
3301}
3302
3303/**
Owen Taylor3473f882001-02-23 17:55:21 +00003304 * xmlXPathObjectCopy:
3305 * @val: the original object
3306 *
3307 * allocate a new copy of a given object
3308 *
3309 * Returns the newly created object.
3310 */
3311xmlXPathObjectPtr
3312xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3313 xmlXPathObjectPtr ret;
3314
3315 if (val == NULL)
3316 return(NULL);
3317
3318 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3319 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003320 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003321 return(NULL);
3322 }
3323 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3324 switch (val->type) {
3325 case XPATH_BOOLEAN:
3326 case XPATH_NUMBER:
3327 case XPATH_POINT:
3328 case XPATH_RANGE:
3329 break;
3330 case XPATH_STRING:
3331 ret->stringval = xmlStrdup(val->stringval);
3332 break;
3333 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00003334#if 0
3335/*
3336 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
3337 this previous handling is no longer correct, and can cause some serious
3338 problems (ref. bug 145547)
3339*/
Owen Taylor3473f882001-02-23 17:55:21 +00003340 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003341 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003342 xmlNodePtr cur, tmp;
3343 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003344
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003345 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003346 top = xmlNewDoc(NULL);
3347 top->name = (char *)
3348 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003349 ret->user = top;
3350 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003351 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003352 cur = val->nodesetval->nodeTab[0]->children;
3353 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003354 tmp = xmlDocCopyNode(cur, top, 1);
3355 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003356 cur = cur->next;
3357 }
3358 }
William M. Bracke9449c52004-07-11 14:41:20 +00003359
Daniel Veillard9adc0462003-03-24 18:39:54 +00003360 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003361 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003362 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003363 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003364 break;
William M. Bracke9449c52004-07-11 14:41:20 +00003365#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003366 case XPATH_NODESET:
3367 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003368 /* Do not deallocate the copied tree value */
3369 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003370 break;
3371 case XPATH_LOCATIONSET:
3372#ifdef LIBXML_XPTR_ENABLED
3373 {
3374 xmlLocationSetPtr loc = val->user;
3375 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3376 break;
3377 }
3378#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003379 case XPATH_USERS:
3380 ret->user = val->user;
3381 break;
3382 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003383 xmlGenericError(xmlGenericErrorContext,
3384 "xmlXPathObjectCopy: unsupported type %d\n",
3385 val->type);
3386 break;
3387 }
3388 return(ret);
3389}
3390
3391/**
3392 * xmlXPathFreeObject:
3393 * @obj: the object to free
3394 *
3395 * Free up an xmlXPathObjectPtr object.
3396 */
3397void
3398xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3399 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003400 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003401 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00003402#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003403 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003404 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003405 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003406 } else
3407#endif
3408 if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003409 xmlXPathFreeValueTree(obj->nodesetval);
3410 } else {
3411 if (obj->nodesetval != NULL)
3412 xmlXPathFreeNodeSet(obj->nodesetval);
3413 }
Owen Taylor3473f882001-02-23 17:55:21 +00003414#ifdef LIBXML_XPTR_ENABLED
3415 } else if (obj->type == XPATH_LOCATIONSET) {
3416 if (obj->user != NULL)
3417 xmlXPtrFreeLocationSet(obj->user);
3418#endif
3419 } else if (obj->type == XPATH_STRING) {
3420 if (obj->stringval != NULL)
3421 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003422 }
3423
Owen Taylor3473f882001-02-23 17:55:21 +00003424 xmlFree(obj);
3425}
3426
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003427
3428/************************************************************************
3429 * *
3430 * Type Casting Routines *
3431 * *
3432 ************************************************************************/
3433
3434/**
3435 * xmlXPathCastBooleanToString:
3436 * @val: a boolean
3437 *
3438 * Converts a boolean to its string value.
3439 *
3440 * Returns a newly allocated string.
3441 */
3442xmlChar *
3443xmlXPathCastBooleanToString (int val) {
3444 xmlChar *ret;
3445 if (val)
3446 ret = xmlStrdup((const xmlChar *) "true");
3447 else
3448 ret = xmlStrdup((const xmlChar *) "false");
3449 return(ret);
3450}
3451
3452/**
3453 * xmlXPathCastNumberToString:
3454 * @val: a number
3455 *
3456 * Converts a number to its string value.
3457 *
3458 * Returns a newly allocated string.
3459 */
3460xmlChar *
3461xmlXPathCastNumberToString (double val) {
3462 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003463 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003464 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003465 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003466 break;
3467 case -1:
3468 ret = xmlStrdup((const xmlChar *) "-Infinity");
3469 break;
3470 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003471 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003472 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003473 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3474 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003475 } else {
3476 /* could be improved */
3477 char buf[100];
3478 xmlXPathFormatNumber(val, buf, 100);
3479 ret = xmlStrdup((const xmlChar *) buf);
3480 }
3481 }
3482 return(ret);
3483}
3484
3485/**
3486 * xmlXPathCastNodeToString:
3487 * @node: a node
3488 *
3489 * Converts a node to its string value.
3490 *
3491 * Returns a newly allocated string.
3492 */
3493xmlChar *
3494xmlXPathCastNodeToString (xmlNodePtr node) {
3495 return(xmlNodeGetContent(node));
3496}
3497
3498/**
3499 * xmlXPathCastNodeSetToString:
3500 * @ns: a node-set
3501 *
3502 * Converts a node-set to its string value.
3503 *
3504 * Returns a newly allocated string.
3505 */
3506xmlChar *
3507xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3508 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3509 return(xmlStrdup((const xmlChar *) ""));
3510
3511 xmlXPathNodeSetSort(ns);
3512 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3513}
3514
3515/**
3516 * xmlXPathCastToString:
3517 * @val: an XPath object
3518 *
3519 * Converts an existing object to its string() equivalent
3520 *
3521 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003522 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003523 * string object).
3524 */
3525xmlChar *
3526xmlXPathCastToString(xmlXPathObjectPtr val) {
3527 xmlChar *ret = NULL;
3528
3529 if (val == NULL)
3530 return(xmlStrdup((const xmlChar *) ""));
3531 switch (val->type) {
3532 case XPATH_UNDEFINED:
3533#ifdef DEBUG_EXPR
3534 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3535#endif
3536 ret = xmlStrdup((const xmlChar *) "");
3537 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003538 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003539 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003540 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3541 break;
3542 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003543 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003544 case XPATH_BOOLEAN:
3545 ret = xmlXPathCastBooleanToString(val->boolval);
3546 break;
3547 case XPATH_NUMBER: {
3548 ret = xmlXPathCastNumberToString(val->floatval);
3549 break;
3550 }
3551 case XPATH_USERS:
3552 case XPATH_POINT:
3553 case XPATH_RANGE:
3554 case XPATH_LOCATIONSET:
3555 TODO
3556 ret = xmlStrdup((const xmlChar *) "");
3557 break;
3558 }
3559 return(ret);
3560}
3561
3562/**
3563 * xmlXPathConvertString:
3564 * @val: an XPath object
3565 *
3566 * Converts an existing object to its string() equivalent
3567 *
3568 * Returns the new object, the old one is freed (or the operation
3569 * is done directly on @val)
3570 */
3571xmlXPathObjectPtr
3572xmlXPathConvertString(xmlXPathObjectPtr val) {
3573 xmlChar *res = NULL;
3574
3575 if (val == NULL)
3576 return(xmlXPathNewCString(""));
3577
3578 switch (val->type) {
3579 case XPATH_UNDEFINED:
3580#ifdef DEBUG_EXPR
3581 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3582#endif
3583 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003584 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003585 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003586 res = xmlXPathCastNodeSetToString(val->nodesetval);
3587 break;
3588 case XPATH_STRING:
3589 return(val);
3590 case XPATH_BOOLEAN:
3591 res = xmlXPathCastBooleanToString(val->boolval);
3592 break;
3593 case XPATH_NUMBER:
3594 res = xmlXPathCastNumberToString(val->floatval);
3595 break;
3596 case XPATH_USERS:
3597 case XPATH_POINT:
3598 case XPATH_RANGE:
3599 case XPATH_LOCATIONSET:
3600 TODO;
3601 break;
3602 }
3603 xmlXPathFreeObject(val);
3604 if (res == NULL)
3605 return(xmlXPathNewCString(""));
3606 return(xmlXPathWrapString(res));
3607}
3608
3609/**
3610 * xmlXPathCastBooleanToNumber:
3611 * @val: a boolean
3612 *
3613 * Converts a boolean to its number value
3614 *
3615 * Returns the number value
3616 */
3617double
3618xmlXPathCastBooleanToNumber(int val) {
3619 if (val)
3620 return(1.0);
3621 return(0.0);
3622}
3623
3624/**
3625 * xmlXPathCastStringToNumber:
3626 * @val: a string
3627 *
3628 * Converts a string to its number value
3629 *
3630 * Returns the number value
3631 */
3632double
3633xmlXPathCastStringToNumber(const xmlChar * val) {
3634 return(xmlXPathStringEvalNumber(val));
3635}
3636
3637/**
3638 * xmlXPathCastNodeToNumber:
3639 * @node: a node
3640 *
3641 * Converts a node to its number value
3642 *
3643 * Returns the number value
3644 */
3645double
3646xmlXPathCastNodeToNumber (xmlNodePtr node) {
3647 xmlChar *strval;
3648 double ret;
3649
3650 if (node == NULL)
3651 return(xmlXPathNAN);
3652 strval = xmlXPathCastNodeToString(node);
3653 if (strval == NULL)
3654 return(xmlXPathNAN);
3655 ret = xmlXPathCastStringToNumber(strval);
3656 xmlFree(strval);
3657
3658 return(ret);
3659}
3660
3661/**
3662 * xmlXPathCastNodeSetToNumber:
3663 * @ns: a node-set
3664 *
3665 * Converts a node-set to its number value
3666 *
3667 * Returns the number value
3668 */
3669double
3670xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3671 xmlChar *str;
3672 double ret;
3673
3674 if (ns == NULL)
3675 return(xmlXPathNAN);
3676 str = xmlXPathCastNodeSetToString(ns);
3677 ret = xmlXPathCastStringToNumber(str);
3678 xmlFree(str);
3679 return(ret);
3680}
3681
3682/**
3683 * xmlXPathCastToNumber:
3684 * @val: an XPath object
3685 *
3686 * Converts an XPath object to its number value
3687 *
3688 * Returns the number value
3689 */
3690double
3691xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3692 double ret = 0.0;
3693
3694 if (val == NULL)
3695 return(xmlXPathNAN);
3696 switch (val->type) {
3697 case XPATH_UNDEFINED:
3698#ifdef DEGUB_EXPR
3699 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3700#endif
3701 ret = xmlXPathNAN;
3702 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003703 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003704 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003705 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3706 break;
3707 case XPATH_STRING:
3708 ret = xmlXPathCastStringToNumber(val->stringval);
3709 break;
3710 case XPATH_NUMBER:
3711 ret = val->floatval;
3712 break;
3713 case XPATH_BOOLEAN:
3714 ret = xmlXPathCastBooleanToNumber(val->boolval);
3715 break;
3716 case XPATH_USERS:
3717 case XPATH_POINT:
3718 case XPATH_RANGE:
3719 case XPATH_LOCATIONSET:
3720 TODO;
3721 ret = xmlXPathNAN;
3722 break;
3723 }
3724 return(ret);
3725}
3726
3727/**
3728 * xmlXPathConvertNumber:
3729 * @val: an XPath object
3730 *
3731 * Converts an existing object to its number() equivalent
3732 *
3733 * Returns the new object, the old one is freed (or the operation
3734 * is done directly on @val)
3735 */
3736xmlXPathObjectPtr
3737xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3738 xmlXPathObjectPtr ret;
3739
3740 if (val == NULL)
3741 return(xmlXPathNewFloat(0.0));
3742 if (val->type == XPATH_NUMBER)
3743 return(val);
3744 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3745 xmlXPathFreeObject(val);
3746 return(ret);
3747}
3748
3749/**
3750 * xmlXPathCastNumberToBoolean:
3751 * @val: a number
3752 *
3753 * Converts a number to its boolean value
3754 *
3755 * Returns the boolean value
3756 */
3757int
3758xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003759 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003760 return(0);
3761 return(1);
3762}
3763
3764/**
3765 * xmlXPathCastStringToBoolean:
3766 * @val: a string
3767 *
3768 * Converts a string to its boolean value
3769 *
3770 * Returns the boolean value
3771 */
3772int
3773xmlXPathCastStringToBoolean (const xmlChar *val) {
3774 if ((val == NULL) || (xmlStrlen(val) == 0))
3775 return(0);
3776 return(1);
3777}
3778
3779/**
3780 * xmlXPathCastNodeSetToBoolean:
3781 * @ns: a node-set
3782 *
3783 * Converts a node-set to its boolean value
3784 *
3785 * Returns the boolean value
3786 */
3787int
3788xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3789 if ((ns == NULL) || (ns->nodeNr == 0))
3790 return(0);
3791 return(1);
3792}
3793
3794/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003795 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003796 * @val: an XPath object
3797 *
3798 * Converts an XPath object to its boolean value
3799 *
3800 * Returns the boolean value
3801 */
3802int
3803xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3804 int ret = 0;
3805
3806 if (val == NULL)
3807 return(0);
3808 switch (val->type) {
3809 case XPATH_UNDEFINED:
3810#ifdef DEBUG_EXPR
3811 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3812#endif
3813 ret = 0;
3814 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003815 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003816 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003817 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3818 break;
3819 case XPATH_STRING:
3820 ret = xmlXPathCastStringToBoolean(val->stringval);
3821 break;
3822 case XPATH_NUMBER:
3823 ret = xmlXPathCastNumberToBoolean(val->floatval);
3824 break;
3825 case XPATH_BOOLEAN:
3826 ret = val->boolval;
3827 break;
3828 case XPATH_USERS:
3829 case XPATH_POINT:
3830 case XPATH_RANGE:
3831 case XPATH_LOCATIONSET:
3832 TODO;
3833 ret = 0;
3834 break;
3835 }
3836 return(ret);
3837}
3838
3839
3840/**
3841 * xmlXPathConvertBoolean:
3842 * @val: an XPath object
3843 *
3844 * Converts an existing object to its boolean() equivalent
3845 *
3846 * Returns the new object, the old one is freed (or the operation
3847 * is done directly on @val)
3848 */
3849xmlXPathObjectPtr
3850xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3851 xmlXPathObjectPtr ret;
3852
3853 if (val == NULL)
3854 return(xmlXPathNewBoolean(0));
3855 if (val->type == XPATH_BOOLEAN)
3856 return(val);
3857 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3858 xmlXPathFreeObject(val);
3859 return(ret);
3860}
3861
Owen Taylor3473f882001-02-23 17:55:21 +00003862/************************************************************************
3863 * *
3864 * Routines to handle XPath contexts *
3865 * *
3866 ************************************************************************/
3867
3868/**
3869 * xmlXPathNewContext:
3870 * @doc: the XML document
3871 *
3872 * Create a new xmlXPathContext
3873 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003874 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003875 */
3876xmlXPathContextPtr
3877xmlXPathNewContext(xmlDocPtr doc) {
3878 xmlXPathContextPtr ret;
3879
3880 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3881 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003882 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003883 return(NULL);
3884 }
3885 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3886 ret->doc = doc;
3887 ret->node = NULL;
3888
3889 ret->varHash = NULL;
3890
3891 ret->nb_types = 0;
3892 ret->max_types = 0;
3893 ret->types = NULL;
3894
3895 ret->funcHash = xmlHashCreate(0);
3896
3897 ret->nb_axis = 0;
3898 ret->max_axis = 0;
3899 ret->axis = NULL;
3900
3901 ret->nsHash = NULL;
3902 ret->user = NULL;
3903
3904 ret->contextSize = -1;
3905 ret->proximityPosition = -1;
3906
3907 xmlXPathRegisterAllFunctions(ret);
3908
3909 return(ret);
3910}
3911
3912/**
3913 * xmlXPathFreeContext:
3914 * @ctxt: the context to free
3915 *
3916 * Free up an xmlXPathContext
3917 */
3918void
3919xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3920 xmlXPathRegisteredNsCleanup(ctxt);
3921 xmlXPathRegisteredFuncsCleanup(ctxt);
3922 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003923 xmlFree(ctxt);
3924}
3925
3926/************************************************************************
3927 * *
3928 * Routines to handle XPath parser contexts *
3929 * *
3930 ************************************************************************/
3931
3932#define CHECK_CTXT(ctxt) \
3933 if (ctxt == NULL) { \
3934 xmlGenericError(xmlGenericErrorContext, \
3935 "%s:%d Internal error: ctxt == NULL\n", \
3936 __FILE__, __LINE__); \
3937 } \
3938
3939
3940#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00003941 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
3942 (ctxt->doc->children == NULL)) { \
3943 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00003944 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00003945 }
Owen Taylor3473f882001-02-23 17:55:21 +00003946
3947
3948/**
3949 * xmlXPathNewParserContext:
3950 * @str: the XPath expression
3951 * @ctxt: the XPath context
3952 *
3953 * Create a new xmlXPathParserContext
3954 *
3955 * Returns the xmlXPathParserContext just allocated.
3956 */
3957xmlXPathParserContextPtr
3958xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3959 xmlXPathParserContextPtr ret;
3960
3961 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3962 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003963 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003964 return(NULL);
3965 }
3966 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3967 ret->cur = ret->base = str;
3968 ret->context = ctxt;
3969
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003970 ret->comp = xmlXPathNewCompExpr();
3971 if (ret->comp == NULL) {
3972 xmlFree(ret->valueTab);
3973 xmlFree(ret);
3974 return(NULL);
3975 }
Daniel Veillard4773df22004-01-23 13:15:13 +00003976 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
3977 ret->comp->dict = ctxt->dict;
3978 xmlDictReference(ret->comp->dict);
3979 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003980
3981 return(ret);
3982}
3983
3984/**
3985 * xmlXPathCompParserContext:
3986 * @comp: the XPath compiled expression
3987 * @ctxt: the XPath context
3988 *
3989 * Create a new xmlXPathParserContext when processing a compiled expression
3990 *
3991 * Returns the xmlXPathParserContext just allocated.
3992 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003993static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003994xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3995 xmlXPathParserContextPtr ret;
3996
3997 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3998 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003999 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004000 return(NULL);
4001 }
4002 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4003
Owen Taylor3473f882001-02-23 17:55:21 +00004004 /* Allocate the value stack */
4005 ret->valueTab = (xmlXPathObjectPtr *)
4006 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004007 if (ret->valueTab == NULL) {
4008 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004009 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004010 return(NULL);
4011 }
Owen Taylor3473f882001-02-23 17:55:21 +00004012 ret->valueNr = 0;
4013 ret->valueMax = 10;
4014 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004015
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004016 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004017 ret->comp = comp;
4018
Owen Taylor3473f882001-02-23 17:55:21 +00004019 return(ret);
4020}
4021
4022/**
4023 * xmlXPathFreeParserContext:
4024 * @ctxt: the context to free
4025 *
4026 * Free up an xmlXPathParserContext
4027 */
4028void
4029xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
4030 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004031 xmlFree(ctxt->valueTab);
4032 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004033 if (ctxt->comp)
4034 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00004035 xmlFree(ctxt);
4036}
4037
4038/************************************************************************
4039 * *
4040 * The implicit core function library *
4041 * *
4042 ************************************************************************/
4043
Owen Taylor3473f882001-02-23 17:55:21 +00004044/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004045 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00004046 * @node: a node pointer
4047 *
4048 * Function computing the beginning of the string value of the node,
4049 * used to speed up comparisons
4050 *
4051 * Returns an int usable as a hash
4052 */
4053static unsigned int
4054xmlXPathNodeValHash(xmlNodePtr node) {
4055 int len = 2;
4056 const xmlChar * string = NULL;
4057 xmlNodePtr tmp = NULL;
4058 unsigned int ret = 0;
4059
4060 if (node == NULL)
4061 return(0);
4062
Daniel Veillard9adc0462003-03-24 18:39:54 +00004063 if (node->type == XML_DOCUMENT_NODE) {
4064 tmp = xmlDocGetRootElement((xmlDocPtr) node);
4065 if (tmp == NULL)
4066 node = node->children;
4067 else
4068 node = tmp;
4069
4070 if (node == NULL)
4071 return(0);
4072 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004073
4074 switch (node->type) {
4075 case XML_COMMENT_NODE:
4076 case XML_PI_NODE:
4077 case XML_CDATA_SECTION_NODE:
4078 case XML_TEXT_NODE:
4079 string = node->content;
4080 if (string == NULL)
4081 return(0);
4082 if (string[0] == 0)
4083 return(0);
4084 return(((unsigned int) string[0]) +
4085 (((unsigned int) string[1]) << 8));
4086 case XML_NAMESPACE_DECL:
4087 string = ((xmlNsPtr)node)->href;
4088 if (string == NULL)
4089 return(0);
4090 if (string[0] == 0)
4091 return(0);
4092 return(((unsigned int) string[0]) +
4093 (((unsigned int) string[1]) << 8));
4094 case XML_ATTRIBUTE_NODE:
4095 tmp = ((xmlAttrPtr) node)->children;
4096 break;
4097 case XML_ELEMENT_NODE:
4098 tmp = node->children;
4099 break;
4100 default:
4101 return(0);
4102 }
4103 while (tmp != NULL) {
4104 switch (tmp->type) {
4105 case XML_COMMENT_NODE:
4106 case XML_PI_NODE:
4107 case XML_CDATA_SECTION_NODE:
4108 case XML_TEXT_NODE:
4109 string = tmp->content;
4110 break;
4111 case XML_NAMESPACE_DECL:
4112 string = ((xmlNsPtr)tmp)->href;
4113 break;
4114 default:
4115 break;
4116 }
4117 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004118 if (len == 1) {
4119 return(ret + (((unsigned int) string[0]) << 8));
4120 }
4121 if (string[1] == 0) {
4122 len = 1;
4123 ret = (unsigned int) string[0];
4124 } else {
4125 return(((unsigned int) string[0]) +
4126 (((unsigned int) string[1]) << 8));
4127 }
4128 }
4129 /*
4130 * Skip to next node
4131 */
4132 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4133 if (tmp->children->type != XML_ENTITY_DECL) {
4134 tmp = tmp->children;
4135 continue;
4136 }
4137 }
4138 if (tmp == node)
4139 break;
4140
4141 if (tmp->next != NULL) {
4142 tmp = tmp->next;
4143 continue;
4144 }
4145
4146 do {
4147 tmp = tmp->parent;
4148 if (tmp == NULL)
4149 break;
4150 if (tmp == node) {
4151 tmp = NULL;
4152 break;
4153 }
4154 if (tmp->next != NULL) {
4155 tmp = tmp->next;
4156 break;
4157 }
4158 } while (tmp != NULL);
4159 }
4160 return(ret);
4161}
4162
4163/**
4164 * xmlXPathStringHash:
4165 * @string: a string
4166 *
4167 * Function computing the beginning of the string value of the node,
4168 * used to speed up comparisons
4169 *
4170 * Returns an int usable as a hash
4171 */
4172static unsigned int
4173xmlXPathStringHash(const xmlChar * string) {
4174 if (string == NULL)
4175 return((unsigned int) 0);
4176 if (string[0] == 0)
4177 return(0);
4178 return(((unsigned int) string[0]) +
4179 (((unsigned int) string[1]) << 8));
4180}
4181
4182/**
Owen Taylor3473f882001-02-23 17:55:21 +00004183 * xmlXPathCompareNodeSetFloat:
4184 * @ctxt: the XPath Parser context
4185 * @inf: less than (1) or greater than (0)
4186 * @strict: is the comparison strict
4187 * @arg: the node set
4188 * @f: the value
4189 *
4190 * Implement the compare operation between a nodeset and a number
4191 * @ns < @val (1, 1, ...
4192 * @ns <= @val (1, 0, ...
4193 * @ns > @val (0, 1, ...
4194 * @ns >= @val (0, 0, ...
4195 *
4196 * If one object to be compared is a node-set and the other is a number,
4197 * then the comparison will be true if and only if there is a node in the
4198 * node-set such that the result of performing the comparison on the number
4199 * to be compared and on the result of converting the string-value of that
4200 * node to a number using the number function is true.
4201 *
4202 * Returns 0 or 1 depending on the results of the test.
4203 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004204static int
Owen Taylor3473f882001-02-23 17:55:21 +00004205xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4206 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4207 int i, ret = 0;
4208 xmlNodeSetPtr ns;
4209 xmlChar *str2;
4210
4211 if ((f == NULL) || (arg == NULL) ||
4212 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4213 xmlXPathFreeObject(arg);
4214 xmlXPathFreeObject(f);
4215 return(0);
4216 }
4217 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004218 if (ns != NULL) {
4219 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004220 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004221 if (str2 != NULL) {
4222 valuePush(ctxt,
4223 xmlXPathNewString(str2));
4224 xmlFree(str2);
4225 xmlXPathNumberFunction(ctxt, 1);
4226 valuePush(ctxt, xmlXPathObjectCopy(f));
4227 ret = xmlXPathCompareValues(ctxt, inf, strict);
4228 if (ret)
4229 break;
4230 }
4231 }
Owen Taylor3473f882001-02-23 17:55:21 +00004232 }
4233 xmlXPathFreeObject(arg);
4234 xmlXPathFreeObject(f);
4235 return(ret);
4236}
4237
4238/**
4239 * xmlXPathCompareNodeSetString:
4240 * @ctxt: the XPath Parser context
4241 * @inf: less than (1) or greater than (0)
4242 * @strict: is the comparison strict
4243 * @arg: the node set
4244 * @s: the value
4245 *
4246 * Implement the compare operation between a nodeset and a string
4247 * @ns < @val (1, 1, ...
4248 * @ns <= @val (1, 0, ...
4249 * @ns > @val (0, 1, ...
4250 * @ns >= @val (0, 0, ...
4251 *
4252 * If one object to be compared is a node-set and the other is a string,
4253 * then the comparison will be true if and only if there is a node in
4254 * the node-set such that the result of performing the comparison on the
4255 * string-value of the node and the other string is true.
4256 *
4257 * Returns 0 or 1 depending on the results of the test.
4258 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004259static int
Owen Taylor3473f882001-02-23 17:55:21 +00004260xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4261 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4262 int i, ret = 0;
4263 xmlNodeSetPtr ns;
4264 xmlChar *str2;
4265
4266 if ((s == NULL) || (arg == NULL) ||
4267 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4268 xmlXPathFreeObject(arg);
4269 xmlXPathFreeObject(s);
4270 return(0);
4271 }
4272 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004273 if (ns != NULL) {
4274 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004275 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004276 if (str2 != NULL) {
4277 valuePush(ctxt,
4278 xmlXPathNewString(str2));
4279 xmlFree(str2);
4280 valuePush(ctxt, xmlXPathObjectCopy(s));
4281 ret = xmlXPathCompareValues(ctxt, inf, strict);
4282 if (ret)
4283 break;
4284 }
4285 }
Owen Taylor3473f882001-02-23 17:55:21 +00004286 }
4287 xmlXPathFreeObject(arg);
4288 xmlXPathFreeObject(s);
4289 return(ret);
4290}
4291
4292/**
4293 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004294 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004295 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004296 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004297 * @arg2: the second node set object
4298 *
4299 * Implement the compare operation on nodesets:
4300 *
4301 * If both objects to be compared are node-sets, then the comparison
4302 * will be true if and only if there is a node in the first node-set
4303 * and a node in the second node-set such that the result of performing
4304 * the comparison on the string-values of the two nodes is true.
4305 * ....
4306 * When neither object to be compared is a node-set and the operator
4307 * is <=, <, >= or >, then the objects are compared by converting both
4308 * objects to numbers and comparing the numbers according to IEEE 754.
4309 * ....
4310 * The number function converts its argument to a number as follows:
4311 * - a string that consists of optional whitespace followed by an
4312 * optional minus sign followed by a Number followed by whitespace
4313 * is converted to the IEEE 754 number that is nearest (according
4314 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4315 * represented by the string; any other string is converted to NaN
4316 *
4317 * Conclusion all nodes need to be converted first to their string value
4318 * and then the comparison must be done when possible
4319 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004320static int
4321xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004322 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4323 int i, j, init = 0;
4324 double val1;
4325 double *values2;
4326 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004327 xmlNodeSetPtr ns1;
4328 xmlNodeSetPtr ns2;
4329
4330 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004331 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4332 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004333 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004334 }
Owen Taylor3473f882001-02-23 17:55:21 +00004335 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004336 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4337 xmlXPathFreeObject(arg1);
4338 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004339 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004340 }
Owen Taylor3473f882001-02-23 17:55:21 +00004341
4342 ns1 = arg1->nodesetval;
4343 ns2 = arg2->nodesetval;
4344
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004345 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004346 xmlXPathFreeObject(arg1);
4347 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004348 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004349 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004350 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004351 xmlXPathFreeObject(arg1);
4352 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004353 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004354 }
Owen Taylor3473f882001-02-23 17:55:21 +00004355
4356 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4357 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004358 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004359 xmlXPathFreeObject(arg1);
4360 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004361 return(0);
4362 }
4363 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004364 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004365 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004366 continue;
4367 for (j = 0;j < ns2->nodeNr;j++) {
4368 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004369 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004370 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004371 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004372 continue;
4373 if (inf && strict)
4374 ret = (val1 < values2[j]);
4375 else if (inf && !strict)
4376 ret = (val1 <= values2[j]);
4377 else if (!inf && strict)
4378 ret = (val1 > values2[j]);
4379 else if (!inf && !strict)
4380 ret = (val1 >= values2[j]);
4381 if (ret)
4382 break;
4383 }
4384 if (ret)
4385 break;
4386 init = 1;
4387 }
4388 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004389 xmlXPathFreeObject(arg1);
4390 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004391 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004392}
4393
4394/**
4395 * xmlXPathCompareNodeSetValue:
4396 * @ctxt: the XPath Parser context
4397 * @inf: less than (1) or greater than (0)
4398 * @strict: is the comparison strict
4399 * @arg: the node set
4400 * @val: the value
4401 *
4402 * Implement the compare operation between a nodeset and a value
4403 * @ns < @val (1, 1, ...
4404 * @ns <= @val (1, 0, ...
4405 * @ns > @val (0, 1, ...
4406 * @ns >= @val (0, 0, ...
4407 *
4408 * If one object to be compared is a node-set and the other is a boolean,
4409 * then the comparison will be true if and only if the result of performing
4410 * the comparison on the boolean and on the result of converting
4411 * the node-set to a boolean using the boolean function is true.
4412 *
4413 * Returns 0 or 1 depending on the results of the test.
4414 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004415static int
Owen Taylor3473f882001-02-23 17:55:21 +00004416xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4417 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4418 if ((val == NULL) || (arg == NULL) ||
4419 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4420 return(0);
4421
4422 switch(val->type) {
4423 case XPATH_NUMBER:
4424 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4425 case XPATH_NODESET:
4426 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004427 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004428 case XPATH_STRING:
4429 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4430 case XPATH_BOOLEAN:
4431 valuePush(ctxt, arg);
4432 xmlXPathBooleanFunction(ctxt, 1);
4433 valuePush(ctxt, val);
4434 return(xmlXPathCompareValues(ctxt, inf, strict));
4435 default:
4436 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004437 }
4438 return(0);
4439}
4440
4441/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004442 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004443 * @arg: the nodeset object argument
4444 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004445 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004446 *
4447 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4448 * If one object to be compared is a node-set and the other is a string,
4449 * then the comparison will be true if and only if there is a node in
4450 * the node-set such that the result of performing the comparison on the
4451 * string-value of the node and the other string is true.
4452 *
4453 * Returns 0 or 1 depending on the results of the test.
4454 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004455static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004456xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004457{
Owen Taylor3473f882001-02-23 17:55:21 +00004458 int i;
4459 xmlNodeSetPtr ns;
4460 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004461 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004462
4463 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004464 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4465 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004466 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004467 /*
4468 * A NULL nodeset compared with a string is always false
4469 * (since there is no node equal, and no node not equal)
4470 */
4471 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004472 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004473 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004474 for (i = 0; i < ns->nodeNr; i++) {
4475 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4476 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4477 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4478 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004479 if (neq)
4480 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004481 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004482 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4483 if (neq)
4484 continue;
4485 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004486 } else if (neq) {
4487 if (str2 != NULL)
4488 xmlFree(str2);
4489 return (1);
4490 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004491 if (str2 != NULL)
4492 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004493 } else if (neq)
4494 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004495 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004496 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004497}
4498
4499/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004500 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004501 * @arg: the nodeset object argument
4502 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004503 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004504 *
4505 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4506 * If one object to be compared is a node-set and the other is a number,
4507 * then the comparison will be true if and only if there is a node in
4508 * the node-set such that the result of performing the comparison on the
4509 * number to be compared and on the result of converting the string-value
4510 * of that node to a number using the number function is true.
4511 *
4512 * Returns 0 or 1 depending on the results of the test.
4513 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004514static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004515xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4516 xmlXPathObjectPtr arg, double f, int neq) {
4517 int i, ret=0;
4518 xmlNodeSetPtr ns;
4519 xmlChar *str2;
4520 xmlXPathObjectPtr val;
4521 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004522
4523 if ((arg == NULL) ||
4524 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4525 return(0);
4526
William M. Brack0c022ad2002-07-12 00:56:01 +00004527 ns = arg->nodesetval;
4528 if (ns != NULL) {
4529 for (i=0;i<ns->nodeNr;i++) {
4530 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4531 if (str2 != NULL) {
4532 valuePush(ctxt, xmlXPathNewString(str2));
4533 xmlFree(str2);
4534 xmlXPathNumberFunction(ctxt, 1);
4535 val = valuePop(ctxt);
4536 v = val->floatval;
4537 xmlXPathFreeObject(val);
4538 if (!xmlXPathIsNaN(v)) {
4539 if ((!neq) && (v==f)) {
4540 ret = 1;
4541 break;
4542 } else if ((neq) && (v!=f)) {
4543 ret = 1;
4544 break;
4545 }
4546 }
4547 }
4548 }
4549 }
4550
4551 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004552}
4553
4554
4555/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004556 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004557 * @arg1: first nodeset object argument
4558 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004559 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004560 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004561 * Implement the equal / not equal operation on XPath nodesets:
4562 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004563 * If both objects to be compared are node-sets, then the comparison
4564 * will be true if and only if there is a node in the first node-set and
4565 * a node in the second node-set such that the result of performing the
4566 * comparison on the string-values of the two nodes is true.
4567 *
4568 * (needless to say, this is a costly operation)
4569 *
4570 * Returns 0 or 1 depending on the results of the test.
4571 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004572static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004573xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004574 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004575 unsigned int *hashs1;
4576 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004577 xmlChar **values1;
4578 xmlChar **values2;
4579 int ret = 0;
4580 xmlNodeSetPtr ns1;
4581 xmlNodeSetPtr ns2;
4582
4583 if ((arg1 == NULL) ||
4584 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4585 return(0);
4586 if ((arg2 == NULL) ||
4587 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4588 return(0);
4589
4590 ns1 = arg1->nodesetval;
4591 ns2 = arg2->nodesetval;
4592
Daniel Veillard911f49a2001-04-07 15:39:35 +00004593 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004594 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004595 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004596 return(0);
4597
4598 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004599 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004600 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004601 if (neq == 0)
4602 for (i = 0;i < ns1->nodeNr;i++)
4603 for (j = 0;j < ns2->nodeNr;j++)
4604 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4605 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004606
4607 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004608 if (values1 == NULL) {
4609 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004610 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004611 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004612 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4613 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004614 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004615 xmlFree(values1);
4616 return(0);
4617 }
Owen Taylor3473f882001-02-23 17:55:21 +00004618 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4619 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4620 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004621 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004622 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004623 xmlFree(values1);
4624 return(0);
4625 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004626 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4627 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004628 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004629 xmlFree(hashs1);
4630 xmlFree(values1);
4631 xmlFree(values2);
4632 return(0);
4633 }
Owen Taylor3473f882001-02-23 17:55:21 +00004634 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4635 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004636 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004637 for (j = 0;j < ns2->nodeNr;j++) {
4638 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004639 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004640 if (hashs1[i] != hashs2[j]) {
4641 if (neq) {
4642 ret = 1;
4643 break;
4644 }
4645 }
4646 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004647 if (values1[i] == NULL)
4648 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4649 if (values2[j] == NULL)
4650 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004651 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004652 if (ret)
4653 break;
4654 }
Owen Taylor3473f882001-02-23 17:55:21 +00004655 }
4656 if (ret)
4657 break;
4658 }
4659 for (i = 0;i < ns1->nodeNr;i++)
4660 if (values1[i] != NULL)
4661 xmlFree(values1[i]);
4662 for (j = 0;j < ns2->nodeNr;j++)
4663 if (values2[j] != NULL)
4664 xmlFree(values2[j]);
4665 xmlFree(values1);
4666 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004667 xmlFree(hashs1);
4668 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004669 return(ret);
4670}
4671
William M. Brack0c022ad2002-07-12 00:56:01 +00004672static int
4673xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4674 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004675 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004676 /*
4677 *At this point we are assured neither arg1 nor arg2
4678 *is a nodeset, so we can just pick the appropriate routine.
4679 */
Owen Taylor3473f882001-02-23 17:55:21 +00004680 switch (arg1->type) {
4681 case XPATH_UNDEFINED:
4682#ifdef DEBUG_EXPR
4683 xmlGenericError(xmlGenericErrorContext,
4684 "Equal: undefined\n");
4685#endif
4686 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004687 case XPATH_BOOLEAN:
4688 switch (arg2->type) {
4689 case XPATH_UNDEFINED:
4690#ifdef DEBUG_EXPR
4691 xmlGenericError(xmlGenericErrorContext,
4692 "Equal: undefined\n");
4693#endif
4694 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004695 case XPATH_BOOLEAN:
4696#ifdef DEBUG_EXPR
4697 xmlGenericError(xmlGenericErrorContext,
4698 "Equal: %d boolean %d \n",
4699 arg1->boolval, arg2->boolval);
4700#endif
4701 ret = (arg1->boolval == arg2->boolval);
4702 break;
4703 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004704 ret = (arg1->boolval ==
4705 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004706 break;
4707 case XPATH_STRING:
4708 if ((arg2->stringval == NULL) ||
4709 (arg2->stringval[0] == 0)) ret = 0;
4710 else
4711 ret = 1;
4712 ret = (arg1->boolval == ret);
4713 break;
4714 case XPATH_USERS:
4715 case XPATH_POINT:
4716 case XPATH_RANGE:
4717 case XPATH_LOCATIONSET:
4718 TODO
4719 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004720 case XPATH_NODESET:
4721 case XPATH_XSLT_TREE:
4722 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004723 }
4724 break;
4725 case XPATH_NUMBER:
4726 switch (arg2->type) {
4727 case XPATH_UNDEFINED:
4728#ifdef DEBUG_EXPR
4729 xmlGenericError(xmlGenericErrorContext,
4730 "Equal: undefined\n");
4731#endif
4732 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004733 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004734 ret = (arg2->boolval==
4735 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004736 break;
4737 case XPATH_STRING:
4738 valuePush(ctxt, arg2);
4739 xmlXPathNumberFunction(ctxt, 1);
4740 arg2 = valuePop(ctxt);
4741 /* no break on purpose */
4742 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004743 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004744 if (xmlXPathIsNaN(arg1->floatval) ||
4745 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004746 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004747 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4748 if (xmlXPathIsInf(arg2->floatval) == 1)
4749 ret = 1;
4750 else
4751 ret = 0;
4752 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4753 if (xmlXPathIsInf(arg2->floatval) == -1)
4754 ret = 1;
4755 else
4756 ret = 0;
4757 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4758 if (xmlXPathIsInf(arg1->floatval) == 1)
4759 ret = 1;
4760 else
4761 ret = 0;
4762 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4763 if (xmlXPathIsInf(arg1->floatval) == -1)
4764 ret = 1;
4765 else
4766 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004767 } else {
4768 ret = (arg1->floatval == arg2->floatval);
4769 }
Owen Taylor3473f882001-02-23 17:55:21 +00004770 break;
4771 case XPATH_USERS:
4772 case XPATH_POINT:
4773 case XPATH_RANGE:
4774 case XPATH_LOCATIONSET:
4775 TODO
4776 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004777 case XPATH_NODESET:
4778 case XPATH_XSLT_TREE:
4779 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004780 }
4781 break;
4782 case XPATH_STRING:
4783 switch (arg2->type) {
4784 case XPATH_UNDEFINED:
4785#ifdef DEBUG_EXPR
4786 xmlGenericError(xmlGenericErrorContext,
4787 "Equal: undefined\n");
4788#endif
4789 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004790 case XPATH_BOOLEAN:
4791 if ((arg1->stringval == NULL) ||
4792 (arg1->stringval[0] == 0)) ret = 0;
4793 else
4794 ret = 1;
4795 ret = (arg2->boolval == ret);
4796 break;
4797 case XPATH_STRING:
4798 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4799 break;
4800 case XPATH_NUMBER:
4801 valuePush(ctxt, arg1);
4802 xmlXPathNumberFunction(ctxt, 1);
4803 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004804 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004805 if (xmlXPathIsNaN(arg1->floatval) ||
4806 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004807 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004808 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4809 if (xmlXPathIsInf(arg2->floatval) == 1)
4810 ret = 1;
4811 else
4812 ret = 0;
4813 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4814 if (xmlXPathIsInf(arg2->floatval) == -1)
4815 ret = 1;
4816 else
4817 ret = 0;
4818 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4819 if (xmlXPathIsInf(arg1->floatval) == 1)
4820 ret = 1;
4821 else
4822 ret = 0;
4823 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4824 if (xmlXPathIsInf(arg1->floatval) == -1)
4825 ret = 1;
4826 else
4827 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004828 } else {
4829 ret = (arg1->floatval == arg2->floatval);
4830 }
Owen Taylor3473f882001-02-23 17:55:21 +00004831 break;
4832 case XPATH_USERS:
4833 case XPATH_POINT:
4834 case XPATH_RANGE:
4835 case XPATH_LOCATIONSET:
4836 TODO
4837 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004838 case XPATH_NODESET:
4839 case XPATH_XSLT_TREE:
4840 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004841 }
4842 break;
4843 case XPATH_USERS:
4844 case XPATH_POINT:
4845 case XPATH_RANGE:
4846 case XPATH_LOCATIONSET:
4847 TODO
4848 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004849 case XPATH_NODESET:
4850 case XPATH_XSLT_TREE:
4851 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004852 }
4853 xmlXPathFreeObject(arg1);
4854 xmlXPathFreeObject(arg2);
4855 return(ret);
4856}
4857
William M. Brack0c022ad2002-07-12 00:56:01 +00004858/**
4859 * xmlXPathEqualValues:
4860 * @ctxt: the XPath Parser context
4861 *
4862 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4863 *
4864 * Returns 0 or 1 depending on the results of the test.
4865 */
4866int
4867xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4868 xmlXPathObjectPtr arg1, arg2, argtmp;
4869 int ret = 0;
4870
Daniel Veillard6128c012004-11-08 17:16:15 +00004871 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00004872 arg2 = valuePop(ctxt);
4873 arg1 = valuePop(ctxt);
4874 if ((arg1 == NULL) || (arg2 == NULL)) {
4875 if (arg1 != NULL)
4876 xmlXPathFreeObject(arg1);
4877 else
4878 xmlXPathFreeObject(arg2);
4879 XP_ERROR0(XPATH_INVALID_OPERAND);
4880 }
4881
4882 if (arg1 == arg2) {
4883#ifdef DEBUG_EXPR
4884 xmlGenericError(xmlGenericErrorContext,
4885 "Equal: by pointer\n");
4886#endif
4887 return(1);
4888 }
4889
4890 /*
4891 *If either argument is a nodeset, it's a 'special case'
4892 */
4893 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4894 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4895 /*
4896 *Hack it to assure arg1 is the nodeset
4897 */
4898 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4899 argtmp = arg2;
4900 arg2 = arg1;
4901 arg1 = argtmp;
4902 }
4903 switch (arg2->type) {
4904 case XPATH_UNDEFINED:
4905#ifdef DEBUG_EXPR
4906 xmlGenericError(xmlGenericErrorContext,
4907 "Equal: undefined\n");
4908#endif
4909 break;
4910 case XPATH_NODESET:
4911 case XPATH_XSLT_TREE:
4912 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4913 break;
4914 case XPATH_BOOLEAN:
4915 if ((arg1->nodesetval == NULL) ||
4916 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4917 else
4918 ret = 1;
4919 ret = (ret == arg2->boolval);
4920 break;
4921 case XPATH_NUMBER:
4922 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4923 break;
4924 case XPATH_STRING:
4925 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4926 break;
4927 case XPATH_USERS:
4928 case XPATH_POINT:
4929 case XPATH_RANGE:
4930 case XPATH_LOCATIONSET:
4931 TODO
4932 break;
4933 }
4934 xmlXPathFreeObject(arg1);
4935 xmlXPathFreeObject(arg2);
4936 return(ret);
4937 }
4938
4939 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4940}
4941
4942/**
4943 * xmlXPathNotEqualValues:
4944 * @ctxt: the XPath Parser context
4945 *
4946 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4947 *
4948 * Returns 0 or 1 depending on the results of the test.
4949 */
4950int
4951xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4952 xmlXPathObjectPtr arg1, arg2, argtmp;
4953 int ret = 0;
4954
Daniel Veillard6128c012004-11-08 17:16:15 +00004955 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00004956 arg2 = valuePop(ctxt);
4957 arg1 = valuePop(ctxt);
4958 if ((arg1 == NULL) || (arg2 == NULL)) {
4959 if (arg1 != NULL)
4960 xmlXPathFreeObject(arg1);
4961 else
4962 xmlXPathFreeObject(arg2);
4963 XP_ERROR0(XPATH_INVALID_OPERAND);
4964 }
4965
4966 if (arg1 == arg2) {
4967#ifdef DEBUG_EXPR
4968 xmlGenericError(xmlGenericErrorContext,
4969 "NotEqual: by pointer\n");
4970#endif
4971 return(0);
4972 }
4973
4974 /*
4975 *If either argument is a nodeset, it's a 'special case'
4976 */
4977 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4978 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4979 /*
4980 *Hack it to assure arg1 is the nodeset
4981 */
4982 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4983 argtmp = arg2;
4984 arg2 = arg1;
4985 arg1 = argtmp;
4986 }
4987 switch (arg2->type) {
4988 case XPATH_UNDEFINED:
4989#ifdef DEBUG_EXPR
4990 xmlGenericError(xmlGenericErrorContext,
4991 "NotEqual: undefined\n");
4992#endif
4993 break;
4994 case XPATH_NODESET:
4995 case XPATH_XSLT_TREE:
4996 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4997 break;
4998 case XPATH_BOOLEAN:
4999 if ((arg1->nodesetval == NULL) ||
5000 (arg1->nodesetval->nodeNr == 0)) ret = 0;
5001 else
5002 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00005003 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00005004 break;
5005 case XPATH_NUMBER:
5006 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5007 break;
5008 case XPATH_STRING:
5009 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
5010 break;
5011 case XPATH_USERS:
5012 case XPATH_POINT:
5013 case XPATH_RANGE:
5014 case XPATH_LOCATIONSET:
5015 TODO
5016 break;
5017 }
5018 xmlXPathFreeObject(arg1);
5019 xmlXPathFreeObject(arg2);
5020 return(ret);
5021 }
5022
5023 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5024}
Owen Taylor3473f882001-02-23 17:55:21 +00005025
5026/**
5027 * xmlXPathCompareValues:
5028 * @ctxt: the XPath Parser context
5029 * @inf: less than (1) or greater than (0)
5030 * @strict: is the comparison strict
5031 *
5032 * Implement the compare operation on XPath objects:
5033 * @arg1 < @arg2 (1, 1, ...
5034 * @arg1 <= @arg2 (1, 0, ...
5035 * @arg1 > @arg2 (0, 1, ...
5036 * @arg1 >= @arg2 (0, 0, ...
5037 *
5038 * When neither object to be compared is a node-set and the operator is
5039 * <=, <, >=, >, then the objects are compared by converted both objects
5040 * to numbers and comparing the numbers according to IEEE 754. The <
5041 * comparison will be true if and only if the first number is less than the
5042 * second number. The <= comparison will be true if and only if the first
5043 * number is less than or equal to the second number. The > comparison
5044 * will be true if and only if the first number is greater than the second
5045 * number. The >= comparison will be true if and only if the first number
5046 * is greater than or equal to the second number.
5047 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005048 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005049 */
5050int
5051xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005052 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005053 xmlXPathObjectPtr arg1, arg2;
5054
Daniel Veillard6128c012004-11-08 17:16:15 +00005055 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005056 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005057 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005058 if ((arg1 == NULL) || (arg2 == NULL)) {
5059 if (arg1 != NULL)
5060 xmlXPathFreeObject(arg1);
5061 else
5062 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005063 XP_ERROR0(XPATH_INVALID_OPERAND);
5064 }
5065
William M. Brack0c022ad2002-07-12 00:56:01 +00005066 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5067 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5068 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5069 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005070 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005071 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005072 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005073 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5074 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005075 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005076 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5077 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005078 }
5079 }
5080 return(ret);
5081 }
5082
5083 if (arg1->type != XPATH_NUMBER) {
5084 valuePush(ctxt, arg1);
5085 xmlXPathNumberFunction(ctxt, 1);
5086 arg1 = valuePop(ctxt);
5087 }
5088 if (arg1->type != XPATH_NUMBER) {
5089 xmlXPathFreeObject(arg1);
5090 xmlXPathFreeObject(arg2);
5091 XP_ERROR0(XPATH_INVALID_OPERAND);
5092 }
5093 if (arg2->type != XPATH_NUMBER) {
5094 valuePush(ctxt, arg2);
5095 xmlXPathNumberFunction(ctxt, 1);
5096 arg2 = valuePop(ctxt);
5097 }
5098 if (arg2->type != XPATH_NUMBER) {
5099 xmlXPathFreeObject(arg1);
5100 xmlXPathFreeObject(arg2);
5101 XP_ERROR0(XPATH_INVALID_OPERAND);
5102 }
5103 /*
5104 * Add tests for infinity and nan
5105 * => feedback on 3.4 for Inf and NaN
5106 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005107 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005108 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005109 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005110 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005111 arg1i=xmlXPathIsInf(arg1->floatval);
5112 arg2i=xmlXPathIsInf(arg2->floatval);
5113 if (inf && strict) {
5114 if ((arg1i == -1 && arg2i != -1) ||
5115 (arg2i == 1 && arg1i != 1)) {
5116 ret = 1;
5117 } else if (arg1i == 0 && arg2i == 0) {
5118 ret = (arg1->floatval < arg2->floatval);
5119 } else {
5120 ret = 0;
5121 }
5122 }
5123 else if (inf && !strict) {
5124 if (arg1i == -1 || arg2i == 1) {
5125 ret = 1;
5126 } else if (arg1i == 0 && arg2i == 0) {
5127 ret = (arg1->floatval <= arg2->floatval);
5128 } else {
5129 ret = 0;
5130 }
5131 }
5132 else if (!inf && strict) {
5133 if ((arg1i == 1 && arg2i != 1) ||
5134 (arg2i == -1 && arg1i != -1)) {
5135 ret = 1;
5136 } else if (arg1i == 0 && arg2i == 0) {
5137 ret = (arg1->floatval > arg2->floatval);
5138 } else {
5139 ret = 0;
5140 }
5141 }
5142 else if (!inf && !strict) {
5143 if (arg1i == 1 || arg2i == -1) {
5144 ret = 1;
5145 } else if (arg1i == 0 && arg2i == 0) {
5146 ret = (arg1->floatval >= arg2->floatval);
5147 } else {
5148 ret = 0;
5149 }
5150 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005151 }
Owen Taylor3473f882001-02-23 17:55:21 +00005152 xmlXPathFreeObject(arg1);
5153 xmlXPathFreeObject(arg2);
5154 return(ret);
5155}
5156
5157/**
5158 * xmlXPathValueFlipSign:
5159 * @ctxt: the XPath Parser context
5160 *
5161 * Implement the unary - operation on an XPath object
5162 * The numeric operators convert their operands to numbers as if
5163 * by calling the number function.
5164 */
5165void
5166xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005167 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005168 CAST_TO_NUMBER;
5169 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005170 if (xmlXPathIsNaN(ctxt->value->floatval))
5171 ctxt->value->floatval=xmlXPathNAN;
5172 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5173 ctxt->value->floatval=xmlXPathNINF;
5174 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5175 ctxt->value->floatval=xmlXPathPINF;
5176 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005177 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5178 ctxt->value->floatval = xmlXPathNZERO;
5179 else
5180 ctxt->value->floatval = 0;
5181 }
5182 else
5183 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005184}
5185
5186/**
5187 * xmlXPathAddValues:
5188 * @ctxt: the XPath Parser context
5189 *
5190 * Implement the add operation on XPath objects:
5191 * The numeric operators convert their operands to numbers as if
5192 * by calling the number function.
5193 */
5194void
5195xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5196 xmlXPathObjectPtr arg;
5197 double val;
5198
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005199 arg = valuePop(ctxt);
5200 if (arg == NULL)
5201 XP_ERROR(XPATH_INVALID_OPERAND);
5202 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005203 xmlXPathFreeObject(arg);
5204
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005205 CAST_TO_NUMBER;
5206 CHECK_TYPE(XPATH_NUMBER);
5207 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005208}
5209
5210/**
5211 * xmlXPathSubValues:
5212 * @ctxt: the XPath Parser context
5213 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005214 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005215 * The numeric operators convert their operands to numbers as if
5216 * by calling the number function.
5217 */
5218void
5219xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5220 xmlXPathObjectPtr arg;
5221 double val;
5222
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005223 arg = valuePop(ctxt);
5224 if (arg == NULL)
5225 XP_ERROR(XPATH_INVALID_OPERAND);
5226 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005227 xmlXPathFreeObject(arg);
5228
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005229 CAST_TO_NUMBER;
5230 CHECK_TYPE(XPATH_NUMBER);
5231 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005232}
5233
5234/**
5235 * xmlXPathMultValues:
5236 * @ctxt: the XPath Parser context
5237 *
5238 * Implement the multiply operation on XPath objects:
5239 * The numeric operators convert their operands to numbers as if
5240 * by calling the number function.
5241 */
5242void
5243xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5244 xmlXPathObjectPtr arg;
5245 double val;
5246
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005247 arg = valuePop(ctxt);
5248 if (arg == NULL)
5249 XP_ERROR(XPATH_INVALID_OPERAND);
5250 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005251 xmlXPathFreeObject(arg);
5252
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005253 CAST_TO_NUMBER;
5254 CHECK_TYPE(XPATH_NUMBER);
5255 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005256}
5257
5258/**
5259 * xmlXPathDivValues:
5260 * @ctxt: the XPath Parser context
5261 *
5262 * Implement the div operation on XPath objects @arg1 / @arg2:
5263 * The numeric operators convert their operands to numbers as if
5264 * by calling the number function.
5265 */
5266void
5267xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5268 xmlXPathObjectPtr arg;
5269 double val;
5270
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005271 arg = valuePop(ctxt);
5272 if (arg == NULL)
5273 XP_ERROR(XPATH_INVALID_OPERAND);
5274 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005275 xmlXPathFreeObject(arg);
5276
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005277 CAST_TO_NUMBER;
5278 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005279 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5280 ctxt->value->floatval = xmlXPathNAN;
5281 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005282 if (ctxt->value->floatval == 0)
5283 ctxt->value->floatval = xmlXPathNAN;
5284 else if (ctxt->value->floatval > 0)
5285 ctxt->value->floatval = xmlXPathNINF;
5286 else if (ctxt->value->floatval < 0)
5287 ctxt->value->floatval = xmlXPathPINF;
5288 }
5289 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005290 if (ctxt->value->floatval == 0)
5291 ctxt->value->floatval = xmlXPathNAN;
5292 else if (ctxt->value->floatval > 0)
5293 ctxt->value->floatval = xmlXPathPINF;
5294 else if (ctxt->value->floatval < 0)
5295 ctxt->value->floatval = xmlXPathNINF;
5296 } else
5297 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005298}
5299
5300/**
5301 * xmlXPathModValues:
5302 * @ctxt: the XPath Parser context
5303 *
5304 * Implement the mod operation on XPath objects: @arg1 / @arg2
5305 * The numeric operators convert their operands to numbers as if
5306 * by calling the number function.
5307 */
5308void
5309xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5310 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005311 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005312
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005313 arg = valuePop(ctxt);
5314 if (arg == NULL)
5315 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005316 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005317 xmlXPathFreeObject(arg);
5318
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005319 CAST_TO_NUMBER;
5320 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005321 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005322 if (arg2 == 0)
5323 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005324 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005325 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005326 }
Owen Taylor3473f882001-02-23 17:55:21 +00005327}
5328
5329/************************************************************************
5330 * *
5331 * The traversal functions *
5332 * *
5333 ************************************************************************/
5334
Owen Taylor3473f882001-02-23 17:55:21 +00005335/*
5336 * A traversal function enumerates nodes along an axis.
5337 * Initially it must be called with NULL, and it indicates
5338 * termination on the axis by returning NULL.
5339 */
5340typedef xmlNodePtr (*xmlXPathTraversalFunction)
5341 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5342
5343/**
5344 * xmlXPathNextSelf:
5345 * @ctxt: the XPath Parser context
5346 * @cur: the current node in the traversal
5347 *
5348 * Traversal function for the "self" direction
5349 * The self axis contains just the context node itself
5350 *
5351 * Returns the next element following that axis
5352 */
5353xmlNodePtr
5354xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005355 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005356 if (cur == NULL)
5357 return(ctxt->context->node);
5358 return(NULL);
5359}
5360
5361/**
5362 * xmlXPathNextChild:
5363 * @ctxt: the XPath Parser context
5364 * @cur: the current node in the traversal
5365 *
5366 * Traversal function for the "child" direction
5367 * The child axis contains the children of the context node in document order.
5368 *
5369 * Returns the next element following that axis
5370 */
5371xmlNodePtr
5372xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005373 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005374 if (cur == NULL) {
5375 if (ctxt->context->node == NULL) return(NULL);
5376 switch (ctxt->context->node->type) {
5377 case XML_ELEMENT_NODE:
5378 case XML_TEXT_NODE:
5379 case XML_CDATA_SECTION_NODE:
5380 case XML_ENTITY_REF_NODE:
5381 case XML_ENTITY_NODE:
5382 case XML_PI_NODE:
5383 case XML_COMMENT_NODE:
5384 case XML_NOTATION_NODE:
5385 case XML_DTD_NODE:
5386 return(ctxt->context->node->children);
5387 case XML_DOCUMENT_NODE:
5388 case XML_DOCUMENT_TYPE_NODE:
5389 case XML_DOCUMENT_FRAG_NODE:
5390 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005391#ifdef LIBXML_DOCB_ENABLED
5392 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005393#endif
5394 return(((xmlDocPtr) ctxt->context->node)->children);
5395 case XML_ELEMENT_DECL:
5396 case XML_ATTRIBUTE_DECL:
5397 case XML_ENTITY_DECL:
5398 case XML_ATTRIBUTE_NODE:
5399 case XML_NAMESPACE_DECL:
5400 case XML_XINCLUDE_START:
5401 case XML_XINCLUDE_END:
5402 return(NULL);
5403 }
5404 return(NULL);
5405 }
5406 if ((cur->type == XML_DOCUMENT_NODE) ||
5407 (cur->type == XML_HTML_DOCUMENT_NODE))
5408 return(NULL);
5409 return(cur->next);
5410}
5411
5412/**
5413 * xmlXPathNextDescendant:
5414 * @ctxt: the XPath Parser context
5415 * @cur: the current node in the traversal
5416 *
5417 * Traversal function for the "descendant" direction
5418 * the descendant axis contains the descendants of the context node in document
5419 * order; a descendant is a child or a child of a child and so on.
5420 *
5421 * Returns the next element following that axis
5422 */
5423xmlNodePtr
5424xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005425 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005426 if (cur == NULL) {
5427 if (ctxt->context->node == NULL)
5428 return(NULL);
5429 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5430 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5431 return(NULL);
5432
5433 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5434 return(ctxt->context->doc->children);
5435 return(ctxt->context->node->children);
5436 }
5437
Daniel Veillard567e1b42001-08-01 15:53:47 +00005438 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005439 /*
5440 * Do not descend on entities declarations
5441 */
5442 if (cur->children->type != XML_ENTITY_DECL) {
5443 cur = cur->children;
5444 /*
5445 * Skip DTDs
5446 */
5447 if (cur->type != XML_DTD_NODE)
5448 return(cur);
5449 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005450 }
5451
5452 if (cur == ctxt->context->node) return(NULL);
5453
Daniel Veillard68e9e742002-11-16 15:35:11 +00005454 while (cur->next != NULL) {
5455 cur = cur->next;
5456 if ((cur->type != XML_ENTITY_DECL) &&
5457 (cur->type != XML_DTD_NODE))
5458 return(cur);
5459 }
Owen Taylor3473f882001-02-23 17:55:21 +00005460
5461 do {
5462 cur = cur->parent;
5463 if (cur == NULL) return(NULL);
5464 if (cur == ctxt->context->node) return(NULL);
5465 if (cur->next != NULL) {
5466 cur = cur->next;
5467 return(cur);
5468 }
5469 } while (cur != NULL);
5470 return(cur);
5471}
5472
5473/**
5474 * xmlXPathNextDescendantOrSelf:
5475 * @ctxt: the XPath Parser context
5476 * @cur: the current node in the traversal
5477 *
5478 * Traversal function for the "descendant-or-self" direction
5479 * the descendant-or-self axis contains the context node and the descendants
5480 * of the context node in document order; thus the context node is the first
5481 * node on the axis, and the first child of the context node is the second node
5482 * on the axis
5483 *
5484 * Returns the next element following that axis
5485 */
5486xmlNodePtr
5487xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005488 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005489 if (cur == NULL) {
5490 if (ctxt->context->node == NULL)
5491 return(NULL);
5492 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5493 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5494 return(NULL);
5495 return(ctxt->context->node);
5496 }
5497
5498 return(xmlXPathNextDescendant(ctxt, cur));
5499}
5500
5501/**
5502 * xmlXPathNextParent:
5503 * @ctxt: the XPath Parser context
5504 * @cur: the current node in the traversal
5505 *
5506 * Traversal function for the "parent" direction
5507 * The parent axis contains the parent of the context node, if there is one.
5508 *
5509 * Returns the next element following that axis
5510 */
5511xmlNodePtr
5512xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005513 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005514 /*
5515 * the parent of an attribute or namespace node is the element
5516 * to which the attribute or namespace node is attached
5517 * Namespace handling !!!
5518 */
5519 if (cur == NULL) {
5520 if (ctxt->context->node == NULL) return(NULL);
5521 switch (ctxt->context->node->type) {
5522 case XML_ELEMENT_NODE:
5523 case XML_TEXT_NODE:
5524 case XML_CDATA_SECTION_NODE:
5525 case XML_ENTITY_REF_NODE:
5526 case XML_ENTITY_NODE:
5527 case XML_PI_NODE:
5528 case XML_COMMENT_NODE:
5529 case XML_NOTATION_NODE:
5530 case XML_DTD_NODE:
5531 case XML_ELEMENT_DECL:
5532 case XML_ATTRIBUTE_DECL:
5533 case XML_XINCLUDE_START:
5534 case XML_XINCLUDE_END:
5535 case XML_ENTITY_DECL:
5536 if (ctxt->context->node->parent == NULL)
5537 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005538 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005539 ((ctxt->context->node->parent->name[0] == ' ') ||
5540 (xmlStrEqual(ctxt->context->node->parent->name,
5541 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005542 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005543 return(ctxt->context->node->parent);
5544 case XML_ATTRIBUTE_NODE: {
5545 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5546
5547 return(att->parent);
5548 }
5549 case XML_DOCUMENT_NODE:
5550 case XML_DOCUMENT_TYPE_NODE:
5551 case XML_DOCUMENT_FRAG_NODE:
5552 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005553#ifdef LIBXML_DOCB_ENABLED
5554 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005555#endif
5556 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005557 case XML_NAMESPACE_DECL: {
5558 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5559
5560 if ((ns->next != NULL) &&
5561 (ns->next->type != XML_NAMESPACE_DECL))
5562 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005563 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005564 }
Owen Taylor3473f882001-02-23 17:55:21 +00005565 }
5566 }
5567 return(NULL);
5568}
5569
5570/**
5571 * xmlXPathNextAncestor:
5572 * @ctxt: the XPath Parser context
5573 * @cur: the current node in the traversal
5574 *
5575 * Traversal function for the "ancestor" direction
5576 * the ancestor axis contains the ancestors of the context node; the ancestors
5577 * of the context node consist of the parent of context node and the parent's
5578 * parent and so on; the nodes are ordered in reverse document order; thus the
5579 * parent is the first node on the axis, and the parent's parent is the second
5580 * node on the axis
5581 *
5582 * Returns the next element following that axis
5583 */
5584xmlNodePtr
5585xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005586 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005587 /*
5588 * the parent of an attribute or namespace node is the element
5589 * to which the attribute or namespace node is attached
5590 * !!!!!!!!!!!!!
5591 */
5592 if (cur == NULL) {
5593 if (ctxt->context->node == NULL) return(NULL);
5594 switch (ctxt->context->node->type) {
5595 case XML_ELEMENT_NODE:
5596 case XML_TEXT_NODE:
5597 case XML_CDATA_SECTION_NODE:
5598 case XML_ENTITY_REF_NODE:
5599 case XML_ENTITY_NODE:
5600 case XML_PI_NODE:
5601 case XML_COMMENT_NODE:
5602 case XML_DTD_NODE:
5603 case XML_ELEMENT_DECL:
5604 case XML_ATTRIBUTE_DECL:
5605 case XML_ENTITY_DECL:
5606 case XML_NOTATION_NODE:
5607 case XML_XINCLUDE_START:
5608 case XML_XINCLUDE_END:
5609 if (ctxt->context->node->parent == NULL)
5610 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005611 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005612 ((ctxt->context->node->parent->name[0] == ' ') ||
5613 (xmlStrEqual(ctxt->context->node->parent->name,
5614 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005615 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005616 return(ctxt->context->node->parent);
5617 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005618 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005619
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005620 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005621 }
5622 case XML_DOCUMENT_NODE:
5623 case XML_DOCUMENT_TYPE_NODE:
5624 case XML_DOCUMENT_FRAG_NODE:
5625 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005626#ifdef LIBXML_DOCB_ENABLED
5627 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005628#endif
5629 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005630 case XML_NAMESPACE_DECL: {
5631 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5632
5633 if ((ns->next != NULL) &&
5634 (ns->next->type != XML_NAMESPACE_DECL))
5635 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005636 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005637 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005638 }
Owen Taylor3473f882001-02-23 17:55:21 +00005639 }
5640 return(NULL);
5641 }
5642 if (cur == ctxt->context->doc->children)
5643 return((xmlNodePtr) ctxt->context->doc);
5644 if (cur == (xmlNodePtr) ctxt->context->doc)
5645 return(NULL);
5646 switch (cur->type) {
5647 case XML_ELEMENT_NODE:
5648 case XML_TEXT_NODE:
5649 case XML_CDATA_SECTION_NODE:
5650 case XML_ENTITY_REF_NODE:
5651 case XML_ENTITY_NODE:
5652 case XML_PI_NODE:
5653 case XML_COMMENT_NODE:
5654 case XML_NOTATION_NODE:
5655 case XML_DTD_NODE:
5656 case XML_ELEMENT_DECL:
5657 case XML_ATTRIBUTE_DECL:
5658 case XML_ENTITY_DECL:
5659 case XML_XINCLUDE_START:
5660 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005661 if (cur->parent == NULL)
5662 return(NULL);
5663 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005664 ((cur->parent->name[0] == ' ') ||
5665 (xmlStrEqual(cur->parent->name,
5666 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005667 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005668 return(cur->parent);
5669 case XML_ATTRIBUTE_NODE: {
5670 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5671
5672 return(att->parent);
5673 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005674 case XML_NAMESPACE_DECL: {
5675 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5676
5677 if ((ns->next != NULL) &&
5678 (ns->next->type != XML_NAMESPACE_DECL))
5679 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005680 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005681 return(NULL);
5682 }
Owen Taylor3473f882001-02-23 17:55:21 +00005683 case XML_DOCUMENT_NODE:
5684 case XML_DOCUMENT_TYPE_NODE:
5685 case XML_DOCUMENT_FRAG_NODE:
5686 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005687#ifdef LIBXML_DOCB_ENABLED
5688 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005689#endif
5690 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005691 }
5692 return(NULL);
5693}
5694
5695/**
5696 * xmlXPathNextAncestorOrSelf:
5697 * @ctxt: the XPath Parser context
5698 * @cur: the current node in the traversal
5699 *
5700 * Traversal function for the "ancestor-or-self" direction
5701 * he ancestor-or-self axis contains the context node and ancestors of
5702 * the context node in reverse document order; thus the context node is
5703 * the first node on the axis, and the context node's parent the second;
5704 * parent here is defined the same as with the parent axis.
5705 *
5706 * Returns the next element following that axis
5707 */
5708xmlNodePtr
5709xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005710 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005711 if (cur == NULL)
5712 return(ctxt->context->node);
5713 return(xmlXPathNextAncestor(ctxt, cur));
5714}
5715
5716/**
5717 * xmlXPathNextFollowingSibling:
5718 * @ctxt: the XPath Parser context
5719 * @cur: the current node in the traversal
5720 *
5721 * Traversal function for the "following-sibling" direction
5722 * The following-sibling axis contains the following siblings of the context
5723 * node in document order.
5724 *
5725 * Returns the next element following that axis
5726 */
5727xmlNodePtr
5728xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005729 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005730 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5731 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5732 return(NULL);
5733 if (cur == (xmlNodePtr) ctxt->context->doc)
5734 return(NULL);
5735 if (cur == NULL)
5736 return(ctxt->context->node->next);
5737 return(cur->next);
5738}
5739
5740/**
5741 * xmlXPathNextPrecedingSibling:
5742 * @ctxt: the XPath Parser context
5743 * @cur: the current node in the traversal
5744 *
5745 * Traversal function for the "preceding-sibling" direction
5746 * The preceding-sibling axis contains the preceding siblings of the context
5747 * node in reverse document order; the first preceding sibling is first on the
5748 * axis; the sibling preceding that node is the second on the axis and so on.
5749 *
5750 * Returns the next element following that axis
5751 */
5752xmlNodePtr
5753xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005754 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005755 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5756 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5757 return(NULL);
5758 if (cur == (xmlNodePtr) ctxt->context->doc)
5759 return(NULL);
5760 if (cur == NULL)
5761 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005762 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5763 cur = cur->prev;
5764 if (cur == NULL)
5765 return(ctxt->context->node->prev);
5766 }
Owen Taylor3473f882001-02-23 17:55:21 +00005767 return(cur->prev);
5768}
5769
5770/**
5771 * xmlXPathNextFollowing:
5772 * @ctxt: the XPath Parser context
5773 * @cur: the current node in the traversal
5774 *
5775 * Traversal function for the "following" direction
5776 * The following axis contains all nodes in the same document as the context
5777 * node that are after the context node in document order, excluding any
5778 * descendants and excluding attribute nodes and namespace nodes; the nodes
5779 * are ordered in document order
5780 *
5781 * Returns the next element following that axis
5782 */
5783xmlNodePtr
5784xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005785 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005786 if (cur != NULL && cur->children != NULL)
5787 return cur->children ;
5788 if (cur == NULL) cur = ctxt->context->node;
5789 if (cur == NULL) return(NULL) ; /* ERROR */
5790 if (cur->next != NULL) return(cur->next) ;
5791 do {
5792 cur = cur->parent;
5793 if (cur == NULL) return(NULL);
5794 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5795 if (cur->next != NULL) return(cur->next);
5796 } while (cur != NULL);
5797 return(cur);
5798}
5799
5800/*
5801 * xmlXPathIsAncestor:
5802 * @ancestor: the ancestor node
5803 * @node: the current node
5804 *
5805 * Check that @ancestor is a @node's ancestor
5806 *
5807 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5808 */
5809static int
5810xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5811 if ((ancestor == NULL) || (node == NULL)) return(0);
5812 /* nodes need to be in the same document */
5813 if (ancestor->doc != node->doc) return(0);
5814 /* avoid searching if ancestor or node is the root node */
5815 if (ancestor == (xmlNodePtr) node->doc) return(1);
5816 if (node == (xmlNodePtr) ancestor->doc) return(0);
5817 while (node->parent != NULL) {
5818 if (node->parent == ancestor)
5819 return(1);
5820 node = node->parent;
5821 }
5822 return(0);
5823}
5824
5825/**
5826 * xmlXPathNextPreceding:
5827 * @ctxt: the XPath Parser context
5828 * @cur: the current node in the traversal
5829 *
5830 * Traversal function for the "preceding" direction
5831 * the preceding axis contains all nodes in the same document as the context
5832 * node that are before the context node in document order, excluding any
5833 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5834 * ordered in reverse document order
5835 *
5836 * Returns the next element following that axis
5837 */
5838xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005839xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5840{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005841 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005842 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005843 cur = ctxt->context->node;
5844 if (cur == NULL)
5845 return (NULL);
5846 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5847 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005848 do {
5849 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005850 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5851 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005852 }
5853
5854 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005855 if (cur == NULL)
5856 return (NULL);
5857 if (cur == ctxt->context->doc->children)
5858 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005859 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005860 return (cur);
5861}
5862
5863/**
5864 * xmlXPathNextPrecedingInternal:
5865 * @ctxt: the XPath Parser context
5866 * @cur: the current node in the traversal
5867 *
5868 * Traversal function for the "preceding" direction
5869 * the preceding axis contains all nodes in the same document as the context
5870 * node that are before the context node in document order, excluding any
5871 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5872 * ordered in reverse document order
5873 * This is a faster implementation but internal only since it requires a
5874 * state kept in the parser context: ctxt->ancestor.
5875 *
5876 * Returns the next element following that axis
5877 */
5878static xmlNodePtr
5879xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5880 xmlNodePtr cur)
5881{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005882 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005883 if (cur == NULL) {
5884 cur = ctxt->context->node;
5885 if (cur == NULL)
5886 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005887 if (cur->type == XML_NAMESPACE_DECL)
5888 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005889 ctxt->ancestor = cur->parent;
5890 }
5891 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5892 cur = cur->prev;
5893 while (cur->prev == NULL) {
5894 cur = cur->parent;
5895 if (cur == NULL)
5896 return (NULL);
5897 if (cur == ctxt->context->doc->children)
5898 return (NULL);
5899 if (cur != ctxt->ancestor)
5900 return (cur);
5901 ctxt->ancestor = cur->parent;
5902 }
5903 cur = cur->prev;
5904 while (cur->last != NULL)
5905 cur = cur->last;
5906 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005907}
5908
5909/**
5910 * xmlXPathNextNamespace:
5911 * @ctxt: the XPath Parser context
5912 * @cur: the current attribute in the traversal
5913 *
5914 * Traversal function for the "namespace" direction
5915 * the namespace axis contains the namespace nodes of the context node;
5916 * the order of nodes on this axis is implementation-defined; the axis will
5917 * be empty unless the context node is an element
5918 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005919 * We keep the XML namespace node at the end of the list.
5920 *
Owen Taylor3473f882001-02-23 17:55:21 +00005921 * Returns the next element following that axis
5922 */
5923xmlNodePtr
5924xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005925 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005926 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005927 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005928 if (ctxt->context->tmpNsList != NULL)
5929 xmlFree(ctxt->context->tmpNsList);
5930 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005931 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005932 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005933 if (ctxt->context->tmpNsList != NULL) {
5934 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5935 ctxt->context->tmpNsNr++;
5936 }
5937 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005938 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005939 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005940 if (ctxt->context->tmpNsNr > 0) {
5941 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5942 } else {
5943 if (ctxt->context->tmpNsList != NULL)
5944 xmlFree(ctxt->context->tmpNsList);
5945 ctxt->context->tmpNsList = NULL;
5946 return(NULL);
5947 }
Owen Taylor3473f882001-02-23 17:55:21 +00005948}
5949
5950/**
5951 * xmlXPathNextAttribute:
5952 * @ctxt: the XPath Parser context
5953 * @cur: the current attribute in the traversal
5954 *
5955 * Traversal function for the "attribute" direction
5956 * TODO: support DTD inherited default attributes
5957 *
5958 * Returns the next element following that axis
5959 */
5960xmlNodePtr
5961xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005962 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00005963 if (ctxt->context->node == NULL)
5964 return(NULL);
5965 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5966 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005967 if (cur == NULL) {
5968 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5969 return(NULL);
5970 return((xmlNodePtr)ctxt->context->node->properties);
5971 }
5972 return((xmlNodePtr)cur->next);
5973}
5974
5975/************************************************************************
5976 * *
5977 * NodeTest Functions *
5978 * *
5979 ************************************************************************/
5980
Owen Taylor3473f882001-02-23 17:55:21 +00005981#define IS_FUNCTION 200
5982
Owen Taylor3473f882001-02-23 17:55:21 +00005983
5984/************************************************************************
5985 * *
5986 * Implicit tree core function library *
5987 * *
5988 ************************************************************************/
5989
5990/**
5991 * xmlXPathRoot:
5992 * @ctxt: the XPath Parser context
5993 *
5994 * Initialize the context to the root of the document
5995 */
5996void
5997xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005998 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00005999 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
6000 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6001}
6002
6003/************************************************************************
6004 * *
6005 * The explicit core function library *
6006 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
6007 * *
6008 ************************************************************************/
6009
6010
6011/**
6012 * xmlXPathLastFunction:
6013 * @ctxt: the XPath Parser context
6014 * @nargs: the number of arguments
6015 *
6016 * Implement the last() XPath function
6017 * number last()
6018 * The last function returns the number of nodes in the context node list.
6019 */
6020void
6021xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6022 CHECK_ARITY(0);
6023 if (ctxt->context->contextSize >= 0) {
6024 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
6025#ifdef DEBUG_EXPR
6026 xmlGenericError(xmlGenericErrorContext,
6027 "last() : %d\n", ctxt->context->contextSize);
6028#endif
6029 } else {
6030 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6031 }
6032}
6033
6034/**
6035 * xmlXPathPositionFunction:
6036 * @ctxt: the XPath Parser context
6037 * @nargs: the number of arguments
6038 *
6039 * Implement the position() XPath function
6040 * number position()
6041 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006042 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00006043 * will be equal to last().
6044 */
6045void
6046xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6047 CHECK_ARITY(0);
6048 if (ctxt->context->proximityPosition >= 0) {
6049 valuePush(ctxt,
6050 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6051#ifdef DEBUG_EXPR
6052 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6053 ctxt->context->proximityPosition);
6054#endif
6055 } else {
6056 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6057 }
6058}
6059
6060/**
6061 * xmlXPathCountFunction:
6062 * @ctxt: the XPath Parser context
6063 * @nargs: the number of arguments
6064 *
6065 * Implement the count() XPath function
6066 * number count(node-set)
6067 */
6068void
6069xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6070 xmlXPathObjectPtr cur;
6071
6072 CHECK_ARITY(1);
6073 if ((ctxt->value == NULL) ||
6074 ((ctxt->value->type != XPATH_NODESET) &&
6075 (ctxt->value->type != XPATH_XSLT_TREE)))
6076 XP_ERROR(XPATH_INVALID_TYPE);
6077 cur = valuePop(ctxt);
6078
Daniel Veillard911f49a2001-04-07 15:39:35 +00006079 if ((cur == NULL) || (cur->nodesetval == NULL))
6080 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006081 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006082 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006083 } else {
6084 if ((cur->nodesetval->nodeNr != 1) ||
6085 (cur->nodesetval->nodeTab == NULL)) {
6086 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6087 } else {
6088 xmlNodePtr tmp;
6089 int i = 0;
6090
6091 tmp = cur->nodesetval->nodeTab[0];
6092 if (tmp != NULL) {
6093 tmp = tmp->children;
6094 while (tmp != NULL) {
6095 tmp = tmp->next;
6096 i++;
6097 }
6098 }
6099 valuePush(ctxt, xmlXPathNewFloat((double) i));
6100 }
6101 }
Owen Taylor3473f882001-02-23 17:55:21 +00006102 xmlXPathFreeObject(cur);
6103}
6104
6105/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006106 * xmlXPathGetElementsByIds:
6107 * @doc: the document
6108 * @ids: a whitespace separated list of IDs
6109 *
6110 * Selects elements by their unique ID.
6111 *
6112 * Returns a node-set of selected elements.
6113 */
6114static xmlNodeSetPtr
6115xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6116 xmlNodeSetPtr ret;
6117 const xmlChar *cur = ids;
6118 xmlChar *ID;
6119 xmlAttrPtr attr;
6120 xmlNodePtr elem = NULL;
6121
Daniel Veillard7a985a12003-07-06 17:57:42 +00006122 if (ids == NULL) return(NULL);
6123
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006124 ret = xmlXPathNodeSetCreate(NULL);
6125
William M. Brack76e95df2003-10-18 16:20:14 +00006126 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006127 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006128 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006129 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006130
6131 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006132 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00006133 /*
6134 * We used to check the fact that the value passed
6135 * was an NCName, but this generated much troubles for
6136 * me and Aleksey Sanin, people blatantly violated that
6137 * constaint, like Visa3D spec.
6138 * if (xmlValidateNCName(ID, 1) == 0)
6139 */
6140 attr = xmlGetID(doc, ID);
6141 if (attr != NULL) {
6142 if (attr->type == XML_ATTRIBUTE_NODE)
6143 elem = attr->parent;
6144 else if (attr->type == XML_ELEMENT_NODE)
6145 elem = (xmlNodePtr) attr;
6146 else
6147 elem = NULL;
6148 if (elem != NULL)
6149 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00006150 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006151 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006152 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006153
William M. Brack76e95df2003-10-18 16:20:14 +00006154 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006155 ids = cur;
6156 }
6157 return(ret);
6158}
6159
6160/**
Owen Taylor3473f882001-02-23 17:55:21 +00006161 * xmlXPathIdFunction:
6162 * @ctxt: the XPath Parser context
6163 * @nargs: the number of arguments
6164 *
6165 * Implement the id() XPath function
6166 * node-set id(object)
6167 * The id function selects elements by their unique ID
6168 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6169 * then the result is the union of the result of applying id to the
6170 * string value of each of the nodes in the argument node-set. When the
6171 * argument to id is of any other type, the argument is converted to a
6172 * string as if by a call to the string function; the string is split
6173 * into a whitespace-separated list of tokens (whitespace is any sequence
6174 * of characters matching the production S); the result is a node-set
6175 * containing the elements in the same document as the context node that
6176 * have a unique ID equal to any of the tokens in the list.
6177 */
6178void
6179xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006180 xmlChar *tokens;
6181 xmlNodeSetPtr ret;
6182 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006183
6184 CHECK_ARITY(1);
6185 obj = valuePop(ctxt);
6186 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006187 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006188 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006189 int i;
6190
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006191 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006192
Daniel Veillard911f49a2001-04-07 15:39:35 +00006193 if (obj->nodesetval != NULL) {
6194 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006195 tokens =
6196 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6197 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6198 ret = xmlXPathNodeSetMerge(ret, ns);
6199 xmlXPathFreeNodeSet(ns);
6200 if (tokens != NULL)
6201 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006202 }
Owen Taylor3473f882001-02-23 17:55:21 +00006203 }
6204
6205 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006206 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006207 return;
6208 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006209 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006210
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006211 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6212 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006213
Owen Taylor3473f882001-02-23 17:55:21 +00006214 xmlXPathFreeObject(obj);
6215 return;
6216}
6217
6218/**
6219 * xmlXPathLocalNameFunction:
6220 * @ctxt: the XPath Parser context
6221 * @nargs: the number of arguments
6222 *
6223 * Implement the local-name() XPath function
6224 * string local-name(node-set?)
6225 * The local-name function returns a string containing the local part
6226 * of the name of the node in the argument node-set that is first in
6227 * document order. If the node-set is empty or the first node has no
6228 * name, an empty string is returned. If the argument is omitted it
6229 * defaults to the context node.
6230 */
6231void
6232xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6233 xmlXPathObjectPtr cur;
6234
Daniel Veillarda82b1822004-11-08 16:24:57 +00006235 if (ctxt == NULL) return;
6236
Owen Taylor3473f882001-02-23 17:55:21 +00006237 if (nargs == 0) {
6238 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6239 nargs = 1;
6240 }
6241
6242 CHECK_ARITY(1);
6243 if ((ctxt->value == NULL) ||
6244 ((ctxt->value->type != XPATH_NODESET) &&
6245 (ctxt->value->type != XPATH_XSLT_TREE)))
6246 XP_ERROR(XPATH_INVALID_TYPE);
6247 cur = valuePop(ctxt);
6248
Daniel Veillard911f49a2001-04-07 15:39:35 +00006249 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006250 valuePush(ctxt, xmlXPathNewCString(""));
6251 } else {
6252 int i = 0; /* Should be first in document order !!!!! */
6253 switch (cur->nodesetval->nodeTab[i]->type) {
6254 case XML_ELEMENT_NODE:
6255 case XML_ATTRIBUTE_NODE:
6256 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006257 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6258 valuePush(ctxt, xmlXPathNewCString(""));
6259 else
6260 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006261 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6262 break;
6263 case XML_NAMESPACE_DECL:
6264 valuePush(ctxt, xmlXPathNewString(
6265 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6266 break;
6267 default:
6268 valuePush(ctxt, xmlXPathNewCString(""));
6269 }
6270 }
6271 xmlXPathFreeObject(cur);
6272}
6273
6274/**
6275 * xmlXPathNamespaceURIFunction:
6276 * @ctxt: the XPath Parser context
6277 * @nargs: the number of arguments
6278 *
6279 * Implement the namespace-uri() XPath function
6280 * string namespace-uri(node-set?)
6281 * The namespace-uri function returns a string containing the
6282 * namespace URI of the expanded name of the node in the argument
6283 * node-set that is first in document order. If the node-set is empty,
6284 * the first node has no name, or the expanded name has no namespace
6285 * URI, an empty string is returned. If the argument is omitted it
6286 * defaults to the context node.
6287 */
6288void
6289xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6290 xmlXPathObjectPtr cur;
6291
Daniel Veillarda82b1822004-11-08 16:24:57 +00006292 if (ctxt == NULL) return;
6293
Owen Taylor3473f882001-02-23 17:55:21 +00006294 if (nargs == 0) {
6295 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6296 nargs = 1;
6297 }
6298 CHECK_ARITY(1);
6299 if ((ctxt->value == NULL) ||
6300 ((ctxt->value->type != XPATH_NODESET) &&
6301 (ctxt->value->type != XPATH_XSLT_TREE)))
6302 XP_ERROR(XPATH_INVALID_TYPE);
6303 cur = valuePop(ctxt);
6304
Daniel Veillard911f49a2001-04-07 15:39:35 +00006305 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006306 valuePush(ctxt, xmlXPathNewCString(""));
6307 } else {
6308 int i = 0; /* Should be first in document order !!!!! */
6309 switch (cur->nodesetval->nodeTab[i]->type) {
6310 case XML_ELEMENT_NODE:
6311 case XML_ATTRIBUTE_NODE:
6312 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6313 valuePush(ctxt, xmlXPathNewCString(""));
6314 else
6315 valuePush(ctxt, xmlXPathNewString(
6316 cur->nodesetval->nodeTab[i]->ns->href));
6317 break;
6318 default:
6319 valuePush(ctxt, xmlXPathNewCString(""));
6320 }
6321 }
6322 xmlXPathFreeObject(cur);
6323}
6324
6325/**
6326 * xmlXPathNameFunction:
6327 * @ctxt: the XPath Parser context
6328 * @nargs: the number of arguments
6329 *
6330 * Implement the name() XPath function
6331 * string name(node-set?)
6332 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006333 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006334 * order. The QName must represent the name with respect to the namespace
6335 * declarations in effect on the node whose name is being represented.
6336 * Typically, this will be the form in which the name occurred in the XML
6337 * source. This need not be the case if there are namespace declarations
6338 * in effect on the node that associate multiple prefixes with the same
6339 * namespace. However, an implementation may include information about
6340 * the original prefix in its representation of nodes; in this case, an
6341 * implementation can ensure that the returned string is always the same
6342 * as the QName used in the XML source. If the argument it omitted it
6343 * defaults to the context node.
6344 * Libxml keep the original prefix so the "real qualified name" used is
6345 * returned.
6346 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006347static void
Daniel Veillard04383752001-07-08 14:27:15 +00006348xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6349{
Owen Taylor3473f882001-02-23 17:55:21 +00006350 xmlXPathObjectPtr cur;
6351
6352 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006353 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6354 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006355 }
6356
6357 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006358 if ((ctxt->value == NULL) ||
6359 ((ctxt->value->type != XPATH_NODESET) &&
6360 (ctxt->value->type != XPATH_XSLT_TREE)))
6361 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006362 cur = valuePop(ctxt);
6363
Daniel Veillard911f49a2001-04-07 15:39:35 +00006364 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006365 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006366 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006367 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006368
Daniel Veillard04383752001-07-08 14:27:15 +00006369 switch (cur->nodesetval->nodeTab[i]->type) {
6370 case XML_ELEMENT_NODE:
6371 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006372 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6373 valuePush(ctxt, xmlXPathNewCString(""));
6374 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6375 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006376 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006377 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006378
Daniel Veillard652d8a92003-02-04 19:28:49 +00006379 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006380 xmlChar *fullname;
6381
6382 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6383 cur->nodesetval->nodeTab[i]->ns->prefix,
6384 NULL, 0);
6385 if (fullname == cur->nodesetval->nodeTab[i]->name)
6386 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6387 if (fullname == NULL) {
6388 XP_ERROR(XPATH_MEMORY_ERROR);
6389 }
6390 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006391 }
6392 break;
6393 default:
6394 valuePush(ctxt,
6395 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6396 xmlXPathLocalNameFunction(ctxt, 1);
6397 }
Owen Taylor3473f882001-02-23 17:55:21 +00006398 }
6399 xmlXPathFreeObject(cur);
6400}
6401
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006402
6403/**
Owen Taylor3473f882001-02-23 17:55:21 +00006404 * xmlXPathStringFunction:
6405 * @ctxt: the XPath Parser context
6406 * @nargs: the number of arguments
6407 *
6408 * Implement the string() XPath function
6409 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006410 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006411 * - A node-set is converted to a string by returning the value of
6412 * the node in the node-set that is first in document order.
6413 * If the node-set is empty, an empty string is returned.
6414 * - A number is converted to a string as follows
6415 * + NaN is converted to the string NaN
6416 * + positive zero is converted to the string 0
6417 * + negative zero is converted to the string 0
6418 * + positive infinity is converted to the string Infinity
6419 * + negative infinity is converted to the string -Infinity
6420 * + if the number is an integer, the number is represented in
6421 * decimal form as a Number with no decimal point and no leading
6422 * zeros, preceded by a minus sign (-) if the number is negative
6423 * + otherwise, the number is represented in decimal form as a
6424 * Number including a decimal point with at least one digit
6425 * before the decimal point and at least one digit after the
6426 * decimal point, preceded by a minus sign (-) if the number
6427 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006428 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006429 * before the decimal point; beyond the one required digit
6430 * after the decimal point there must be as many, but only as
6431 * many, more digits as are needed to uniquely distinguish the
6432 * number from all other IEEE 754 numeric values.
6433 * - The boolean false value is converted to the string false.
6434 * The boolean true value is converted to the string true.
6435 *
6436 * If the argument is omitted, it defaults to a node-set with the
6437 * context node as its only member.
6438 */
6439void
6440xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6441 xmlXPathObjectPtr cur;
6442
Daniel Veillarda82b1822004-11-08 16:24:57 +00006443 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006444 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006445 valuePush(ctxt,
6446 xmlXPathWrapString(
6447 xmlXPathCastNodeToString(ctxt->context->node)));
6448 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006449 }
6450
6451 CHECK_ARITY(1);
6452 cur = valuePop(ctxt);
6453 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006454 cur = xmlXPathConvertString(cur);
6455 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006456}
6457
6458/**
6459 * xmlXPathStringLengthFunction:
6460 * @ctxt: the XPath Parser context
6461 * @nargs: the number of arguments
6462 *
6463 * Implement the string-length() XPath function
6464 * number string-length(string?)
6465 * The string-length returns the number of characters in the string
6466 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6467 * the context node converted to a string, in other words the value
6468 * of the context node.
6469 */
6470void
6471xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6472 xmlXPathObjectPtr cur;
6473
6474 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006475 if ((ctxt == NULL) || (ctxt->context == NULL))
6476 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006477 if (ctxt->context->node == NULL) {
6478 valuePush(ctxt, xmlXPathNewFloat(0));
6479 } else {
6480 xmlChar *content;
6481
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006482 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006483 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006484 xmlFree(content);
6485 }
6486 return;
6487 }
6488 CHECK_ARITY(1);
6489 CAST_TO_STRING;
6490 CHECK_TYPE(XPATH_STRING);
6491 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006492 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006493 xmlXPathFreeObject(cur);
6494}
6495
6496/**
6497 * xmlXPathConcatFunction:
6498 * @ctxt: the XPath Parser context
6499 * @nargs: the number of arguments
6500 *
6501 * Implement the concat() XPath function
6502 * string concat(string, string, string*)
6503 * The concat function returns the concatenation of its arguments.
6504 */
6505void
6506xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6507 xmlXPathObjectPtr cur, newobj;
6508 xmlChar *tmp;
6509
Daniel Veillarda82b1822004-11-08 16:24:57 +00006510 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006511 if (nargs < 2) {
6512 CHECK_ARITY(2);
6513 }
6514
6515 CAST_TO_STRING;
6516 cur = valuePop(ctxt);
6517 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6518 xmlXPathFreeObject(cur);
6519 return;
6520 }
6521 nargs--;
6522
6523 while (nargs > 0) {
6524 CAST_TO_STRING;
6525 newobj = valuePop(ctxt);
6526 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6527 xmlXPathFreeObject(newobj);
6528 xmlXPathFreeObject(cur);
6529 XP_ERROR(XPATH_INVALID_TYPE);
6530 }
6531 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6532 newobj->stringval = cur->stringval;
6533 cur->stringval = tmp;
6534
6535 xmlXPathFreeObject(newobj);
6536 nargs--;
6537 }
6538 valuePush(ctxt, cur);
6539}
6540
6541/**
6542 * xmlXPathContainsFunction:
6543 * @ctxt: the XPath Parser context
6544 * @nargs: the number of arguments
6545 *
6546 * Implement the contains() XPath function
6547 * boolean contains(string, string)
6548 * The contains function returns true if the first argument string
6549 * contains the second argument string, and otherwise returns false.
6550 */
6551void
6552xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6553 xmlXPathObjectPtr hay, needle;
6554
6555 CHECK_ARITY(2);
6556 CAST_TO_STRING;
6557 CHECK_TYPE(XPATH_STRING);
6558 needle = valuePop(ctxt);
6559 CAST_TO_STRING;
6560 hay = valuePop(ctxt);
6561 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6562 xmlXPathFreeObject(hay);
6563 xmlXPathFreeObject(needle);
6564 XP_ERROR(XPATH_INVALID_TYPE);
6565 }
6566 if (xmlStrstr(hay->stringval, needle->stringval))
6567 valuePush(ctxt, xmlXPathNewBoolean(1));
6568 else
6569 valuePush(ctxt, xmlXPathNewBoolean(0));
6570 xmlXPathFreeObject(hay);
6571 xmlXPathFreeObject(needle);
6572}
6573
6574/**
6575 * xmlXPathStartsWithFunction:
6576 * @ctxt: the XPath Parser context
6577 * @nargs: the number of arguments
6578 *
6579 * Implement the starts-with() XPath function
6580 * boolean starts-with(string, string)
6581 * The starts-with function returns true if the first argument string
6582 * starts with the second argument string, and otherwise returns false.
6583 */
6584void
6585xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6586 xmlXPathObjectPtr hay, needle;
6587 int n;
6588
6589 CHECK_ARITY(2);
6590 CAST_TO_STRING;
6591 CHECK_TYPE(XPATH_STRING);
6592 needle = valuePop(ctxt);
6593 CAST_TO_STRING;
6594 hay = valuePop(ctxt);
6595 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6596 xmlXPathFreeObject(hay);
6597 xmlXPathFreeObject(needle);
6598 XP_ERROR(XPATH_INVALID_TYPE);
6599 }
6600 n = xmlStrlen(needle->stringval);
6601 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6602 valuePush(ctxt, xmlXPathNewBoolean(0));
6603 else
6604 valuePush(ctxt, xmlXPathNewBoolean(1));
6605 xmlXPathFreeObject(hay);
6606 xmlXPathFreeObject(needle);
6607}
6608
6609/**
6610 * xmlXPathSubstringFunction:
6611 * @ctxt: the XPath Parser context
6612 * @nargs: the number of arguments
6613 *
6614 * Implement the substring() XPath function
6615 * string substring(string, number, number?)
6616 * The substring function returns the substring of the first argument
6617 * starting at the position specified in the second argument with
6618 * length specified in the third argument. For example,
6619 * substring("12345",2,3) returns "234". If the third argument is not
6620 * specified, it returns the substring starting at the position specified
6621 * in the second argument and continuing to the end of the string. For
6622 * example, substring("12345",2) returns "2345". More precisely, each
6623 * character in the string (see [3.6 Strings]) is considered to have a
6624 * numeric position: the position of the first character is 1, the position
6625 * of the second character is 2 and so on. The returned substring contains
6626 * those characters for which the position of the character is greater than
6627 * or equal to the second argument and, if the third argument is specified,
6628 * less than the sum of the second and third arguments; the comparisons
6629 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6630 * - substring("12345", 1.5, 2.6) returns "234"
6631 * - substring("12345", 0, 3) returns "12"
6632 * - substring("12345", 0 div 0, 3) returns ""
6633 * - substring("12345", 1, 0 div 0) returns ""
6634 * - substring("12345", -42, 1 div 0) returns "12345"
6635 * - substring("12345", -1 div 0, 1 div 0) returns ""
6636 */
6637void
6638xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6639 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006640 double le=0, in;
6641 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006642 xmlChar *ret;
6643
Owen Taylor3473f882001-02-23 17:55:21 +00006644 if (nargs < 2) {
6645 CHECK_ARITY(2);
6646 }
6647 if (nargs > 3) {
6648 CHECK_ARITY(3);
6649 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006650 /*
6651 * take care of possible last (position) argument
6652 */
Owen Taylor3473f882001-02-23 17:55:21 +00006653 if (nargs == 3) {
6654 CAST_TO_NUMBER;
6655 CHECK_TYPE(XPATH_NUMBER);
6656 len = valuePop(ctxt);
6657 le = len->floatval;
6658 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006659 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006660
Owen Taylor3473f882001-02-23 17:55:21 +00006661 CAST_TO_NUMBER;
6662 CHECK_TYPE(XPATH_NUMBER);
6663 start = valuePop(ctxt);
6664 in = start->floatval;
6665 xmlXPathFreeObject(start);
6666 CAST_TO_STRING;
6667 CHECK_TYPE(XPATH_STRING);
6668 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006669 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006670
Daniel Veillard97ac1312001-05-30 19:14:17 +00006671 /*
6672 * If last pos not present, calculate last position
6673 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006674 if (nargs != 3) {
6675 le = (double)m;
6676 if (in < 1.0)
6677 in = 1.0;
6678 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006679
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006680 /* Need to check for the special cases where either
6681 * the index is NaN, the length is NaN, or both
6682 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006683 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006684 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006685 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006686 * To meet the requirements of the spec, the arguments
6687 * must be converted to integer format before
6688 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006689 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006690 * First we go to integer form, rounding up
6691 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006692 */
6693 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006694 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006695
Daniel Veillard9e412302002-06-10 15:59:44 +00006696 if (xmlXPathIsInf(le) == 1) {
6697 l = m;
6698 if (i < 1)
6699 i = 1;
6700 }
6701 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6702 l = 0;
6703 else {
6704 l = (int) le;
6705 if (((double)l)+0.5 <= le) l++;
6706 }
6707
6708 /* Now we normalize inidices */
6709 i -= 1;
6710 l += i;
6711 if (i < 0)
6712 i = 0;
6713 if (l > m)
6714 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006715
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006716 /* number of chars to copy */
6717 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006718
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006719 ret = xmlUTF8Strsub(str->stringval, i, l);
6720 }
6721 else {
6722 ret = NULL;
6723 }
6724
Owen Taylor3473f882001-02-23 17:55:21 +00006725 if (ret == NULL)
6726 valuePush(ctxt, xmlXPathNewCString(""));
6727 else {
6728 valuePush(ctxt, xmlXPathNewString(ret));
6729 xmlFree(ret);
6730 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006731
Owen Taylor3473f882001-02-23 17:55:21 +00006732 xmlXPathFreeObject(str);
6733}
6734
6735/**
6736 * xmlXPathSubstringBeforeFunction:
6737 * @ctxt: the XPath Parser context
6738 * @nargs: the number of arguments
6739 *
6740 * Implement the substring-before() XPath function
6741 * string substring-before(string, string)
6742 * The substring-before function returns the substring of the first
6743 * argument string that precedes the first occurrence of the second
6744 * argument string in the first argument string, or the empty string
6745 * if the first argument string does not contain the second argument
6746 * string. For example, substring-before("1999/04/01","/") returns 1999.
6747 */
6748void
6749xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6750 xmlXPathObjectPtr str;
6751 xmlXPathObjectPtr find;
6752 xmlBufferPtr target;
6753 const xmlChar *point;
6754 int offset;
6755
6756 CHECK_ARITY(2);
6757 CAST_TO_STRING;
6758 find = valuePop(ctxt);
6759 CAST_TO_STRING;
6760 str = valuePop(ctxt);
6761
6762 target = xmlBufferCreate();
6763 if (target) {
6764 point = xmlStrstr(str->stringval, find->stringval);
6765 if (point) {
6766 offset = (int)(point - str->stringval);
6767 xmlBufferAdd(target, str->stringval, offset);
6768 }
6769 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6770 xmlBufferFree(target);
6771 }
6772
6773 xmlXPathFreeObject(str);
6774 xmlXPathFreeObject(find);
6775}
6776
6777/**
6778 * xmlXPathSubstringAfterFunction:
6779 * @ctxt: the XPath Parser context
6780 * @nargs: the number of arguments
6781 *
6782 * Implement the substring-after() XPath function
6783 * string substring-after(string, string)
6784 * The substring-after function returns the substring of the first
6785 * argument string that follows the first occurrence of the second
6786 * argument string in the first argument string, or the empty stringi
6787 * if the first argument string does not contain the second argument
6788 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6789 * and substring-after("1999/04/01","19") returns 99/04/01.
6790 */
6791void
6792xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6793 xmlXPathObjectPtr str;
6794 xmlXPathObjectPtr find;
6795 xmlBufferPtr target;
6796 const xmlChar *point;
6797 int offset;
6798
6799 CHECK_ARITY(2);
6800 CAST_TO_STRING;
6801 find = valuePop(ctxt);
6802 CAST_TO_STRING;
6803 str = valuePop(ctxt);
6804
6805 target = xmlBufferCreate();
6806 if (target) {
6807 point = xmlStrstr(str->stringval, find->stringval);
6808 if (point) {
6809 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6810 xmlBufferAdd(target, &str->stringval[offset],
6811 xmlStrlen(str->stringval) - offset);
6812 }
6813 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6814 xmlBufferFree(target);
6815 }
6816
6817 xmlXPathFreeObject(str);
6818 xmlXPathFreeObject(find);
6819}
6820
6821/**
6822 * xmlXPathNormalizeFunction:
6823 * @ctxt: the XPath Parser context
6824 * @nargs: the number of arguments
6825 *
6826 * Implement the normalize-space() XPath function
6827 * string normalize-space(string?)
6828 * The normalize-space function returns the argument string with white
6829 * space normalized by stripping leading and trailing whitespace
6830 * and replacing sequences of whitespace characters by a single
6831 * space. Whitespace characters are the same allowed by the S production
6832 * in XML. If the argument is omitted, it defaults to the context
6833 * node converted to a string, in other words the value of the context node.
6834 */
6835void
6836xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6837 xmlXPathObjectPtr obj = NULL;
6838 xmlChar *source = NULL;
6839 xmlBufferPtr target;
6840 xmlChar blank;
6841
Daniel Veillarda82b1822004-11-08 16:24:57 +00006842 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006843 if (nargs == 0) {
6844 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006845 valuePush(ctxt,
6846 xmlXPathWrapString(
6847 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006848 nargs = 1;
6849 }
6850
6851 CHECK_ARITY(1);
6852 CAST_TO_STRING;
6853 CHECK_TYPE(XPATH_STRING);
6854 obj = valuePop(ctxt);
6855 source = obj->stringval;
6856
6857 target = xmlBufferCreate();
6858 if (target && source) {
6859
6860 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006861 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006862 source++;
6863
6864 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6865 blank = 0;
6866 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006867 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006868 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006869 } else {
6870 if (blank) {
6871 xmlBufferAdd(target, &blank, 1);
6872 blank = 0;
6873 }
6874 xmlBufferAdd(target, source, 1);
6875 }
6876 source++;
6877 }
6878
6879 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6880 xmlBufferFree(target);
6881 }
6882 xmlXPathFreeObject(obj);
6883}
6884
6885/**
6886 * xmlXPathTranslateFunction:
6887 * @ctxt: the XPath Parser context
6888 * @nargs: the number of arguments
6889 *
6890 * Implement the translate() XPath function
6891 * string translate(string, string, string)
6892 * The translate function returns the first argument string with
6893 * occurrences of characters in the second argument string replaced
6894 * by the character at the corresponding position in the third argument
6895 * string. For example, translate("bar","abc","ABC") returns the string
6896 * BAr. If there is a character in the second argument string with no
6897 * character at a corresponding position in the third argument string
6898 * (because the second argument string is longer than the third argument
6899 * string), then occurrences of that character in the first argument
6900 * string are removed. For example, translate("--aaa--","abc-","ABC")
6901 * returns "AAA". If a character occurs more than once in second
6902 * argument string, then the first occurrence determines the replacement
6903 * character. If the third argument string is longer than the second
6904 * argument string, then excess characters are ignored.
6905 */
6906void
6907xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006908 xmlXPathObjectPtr str;
6909 xmlXPathObjectPtr from;
6910 xmlXPathObjectPtr to;
6911 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006912 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006913 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00006914 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006915 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006916
Daniel Veillarde043ee12001-04-16 14:08:07 +00006917 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006918
Daniel Veillarde043ee12001-04-16 14:08:07 +00006919 CAST_TO_STRING;
6920 to = valuePop(ctxt);
6921 CAST_TO_STRING;
6922 from = valuePop(ctxt);
6923 CAST_TO_STRING;
6924 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006925
Daniel Veillarde043ee12001-04-16 14:08:07 +00006926 target = xmlBufferCreate();
6927 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006928 max = xmlUTF8Strlen(to->stringval);
6929 for (cptr = str->stringval; (ch=*cptr); ) {
6930 offset = xmlUTF8Strloc(from->stringval, cptr);
6931 if (offset >= 0) {
6932 if (offset < max) {
6933 point = xmlUTF8Strpos(to->stringval, offset);
6934 if (point)
6935 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6936 }
6937 } else
6938 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6939
6940 /* Step to next character in input */
6941 cptr++;
6942 if ( ch & 0x80 ) {
6943 /* if not simple ascii, verify proper format */
6944 if ( (ch & 0xc0) != 0xc0 ) {
6945 xmlGenericError(xmlGenericErrorContext,
6946 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6947 break;
6948 }
6949 /* then skip over remaining bytes for this char */
6950 while ( (ch <<= 1) & 0x80 )
6951 if ( (*cptr++ & 0xc0) != 0x80 ) {
6952 xmlGenericError(xmlGenericErrorContext,
6953 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6954 break;
6955 }
6956 if (ch & 0x80) /* must have had error encountered */
6957 break;
6958 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006959 }
Owen Taylor3473f882001-02-23 17:55:21 +00006960 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006961 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6962 xmlBufferFree(target);
6963 xmlXPathFreeObject(str);
6964 xmlXPathFreeObject(from);
6965 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006966}
6967
6968/**
6969 * xmlXPathBooleanFunction:
6970 * @ctxt: the XPath Parser context
6971 * @nargs: the number of arguments
6972 *
6973 * Implement the boolean() XPath function
6974 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00006975 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006976 * - a number is true if and only if it is neither positive or
6977 * negative zero nor NaN
6978 * - a node-set is true if and only if it is non-empty
6979 * - a string is true if and only if its length is non-zero
6980 */
6981void
6982xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6983 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006984
6985 CHECK_ARITY(1);
6986 cur = valuePop(ctxt);
6987 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006988 cur = xmlXPathConvertBoolean(cur);
6989 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006990}
6991
6992/**
6993 * xmlXPathNotFunction:
6994 * @ctxt: the XPath Parser context
6995 * @nargs: the number of arguments
6996 *
6997 * Implement the not() XPath function
6998 * boolean not(boolean)
6999 * The not function returns true if its argument is false,
7000 * and false otherwise.
7001 */
7002void
7003xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7004 CHECK_ARITY(1);
7005 CAST_TO_BOOLEAN;
7006 CHECK_TYPE(XPATH_BOOLEAN);
7007 ctxt->value->boolval = ! ctxt->value->boolval;
7008}
7009
7010/**
7011 * xmlXPathTrueFunction:
7012 * @ctxt: the XPath Parser context
7013 * @nargs: the number of arguments
7014 *
7015 * Implement the true() XPath function
7016 * boolean true()
7017 */
7018void
7019xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7020 CHECK_ARITY(0);
7021 valuePush(ctxt, xmlXPathNewBoolean(1));
7022}
7023
7024/**
7025 * xmlXPathFalseFunction:
7026 * @ctxt: the XPath Parser context
7027 * @nargs: the number of arguments
7028 *
7029 * Implement the false() XPath function
7030 * boolean false()
7031 */
7032void
7033xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7034 CHECK_ARITY(0);
7035 valuePush(ctxt, xmlXPathNewBoolean(0));
7036}
7037
7038/**
7039 * xmlXPathLangFunction:
7040 * @ctxt: the XPath Parser context
7041 * @nargs: the number of arguments
7042 *
7043 * Implement the lang() XPath function
7044 * boolean lang(string)
7045 * The lang function returns true or false depending on whether the
7046 * language of the context node as specified by xml:lang attributes
7047 * is the same as or is a sublanguage of the language specified by
7048 * the argument string. The language of the context node is determined
7049 * by the value of the xml:lang attribute on the context node, or, if
7050 * the context node has no xml:lang attribute, by the value of the
7051 * xml:lang attribute on the nearest ancestor of the context node that
7052 * has an xml:lang attribute. If there is no such attribute, then lang
7053 * returns false. If there is such an attribute, then lang returns
7054 * true if the attribute value is equal to the argument ignoring case,
7055 * or if there is some suffix starting with - such that the attribute
7056 * value is equal to the argument ignoring that suffix of the attribute
7057 * value and ignoring case.
7058 */
7059void
7060xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7061 xmlXPathObjectPtr val;
7062 const xmlChar *theLang;
7063 const xmlChar *lang;
7064 int ret = 0;
7065 int i;
7066
7067 CHECK_ARITY(1);
7068 CAST_TO_STRING;
7069 CHECK_TYPE(XPATH_STRING);
7070 val = valuePop(ctxt);
7071 lang = val->stringval;
7072 theLang = xmlNodeGetLang(ctxt->context->node);
7073 if ((theLang != NULL) && (lang != NULL)) {
7074 for (i = 0;lang[i] != 0;i++)
7075 if (toupper(lang[i]) != toupper(theLang[i]))
7076 goto not_equal;
7077 ret = 1;
7078 }
7079not_equal:
William M. Bracka59ddb52004-02-25 08:12:32 +00007080 xmlFree((void *)theLang);
Owen Taylor3473f882001-02-23 17:55:21 +00007081 xmlXPathFreeObject(val);
7082 valuePush(ctxt, xmlXPathNewBoolean(ret));
7083}
7084
7085/**
7086 * xmlXPathNumberFunction:
7087 * @ctxt: the XPath Parser context
7088 * @nargs: the number of arguments
7089 *
7090 * Implement the number() XPath function
7091 * number number(object?)
7092 */
7093void
7094xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7095 xmlXPathObjectPtr cur;
7096 double res;
7097
Daniel Veillarda82b1822004-11-08 16:24:57 +00007098 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007099 if (nargs == 0) {
7100 if (ctxt->context->node == NULL) {
7101 valuePush(ctxt, xmlXPathNewFloat(0.0));
7102 } else {
7103 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7104
7105 res = xmlXPathStringEvalNumber(content);
7106 valuePush(ctxt, xmlXPathNewFloat(res));
7107 xmlFree(content);
7108 }
7109 return;
7110 }
7111
7112 CHECK_ARITY(1);
7113 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007114 cur = xmlXPathConvertNumber(cur);
7115 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007116}
7117
7118/**
7119 * xmlXPathSumFunction:
7120 * @ctxt: the XPath Parser context
7121 * @nargs: the number of arguments
7122 *
7123 * Implement the sum() XPath function
7124 * number sum(node-set)
7125 * The sum function returns the sum of the values of the nodes in
7126 * the argument node-set.
7127 */
7128void
7129xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7130 xmlXPathObjectPtr cur;
7131 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007132 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007133
7134 CHECK_ARITY(1);
7135 if ((ctxt->value == NULL) ||
7136 ((ctxt->value->type != XPATH_NODESET) &&
7137 (ctxt->value->type != XPATH_XSLT_TREE)))
7138 XP_ERROR(XPATH_INVALID_TYPE);
7139 cur = valuePop(ctxt);
7140
William M. Brack08171912003-12-29 02:52:11 +00007141 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007142 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7143 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007144 }
7145 }
William M. Brack08171912003-12-29 02:52:11 +00007146 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007147 xmlXPathFreeObject(cur);
7148}
7149
7150/**
7151 * xmlXPathFloorFunction:
7152 * @ctxt: the XPath Parser context
7153 * @nargs: the number of arguments
7154 *
7155 * Implement the floor() XPath function
7156 * number floor(number)
7157 * The floor function returns the largest (closest to positive infinity)
7158 * number that is not greater than the argument and that is an integer.
7159 */
7160void
7161xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007162 double f;
7163
Owen Taylor3473f882001-02-23 17:55:21 +00007164 CHECK_ARITY(1);
7165 CAST_TO_NUMBER;
7166 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007167
7168 f = (double)((int) ctxt->value->floatval);
7169 if (f != ctxt->value->floatval) {
7170 if (ctxt->value->floatval > 0)
7171 ctxt->value->floatval = f;
7172 else
7173 ctxt->value->floatval = f - 1;
7174 }
Owen Taylor3473f882001-02-23 17:55:21 +00007175}
7176
7177/**
7178 * xmlXPathCeilingFunction:
7179 * @ctxt: the XPath Parser context
7180 * @nargs: the number of arguments
7181 *
7182 * Implement the ceiling() XPath function
7183 * number ceiling(number)
7184 * The ceiling function returns the smallest (closest to negative infinity)
7185 * number that is not less than the argument and that is an integer.
7186 */
7187void
7188xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7189 double f;
7190
7191 CHECK_ARITY(1);
7192 CAST_TO_NUMBER;
7193 CHECK_TYPE(XPATH_NUMBER);
7194
7195#if 0
7196 ctxt->value->floatval = ceil(ctxt->value->floatval);
7197#else
7198 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007199 if (f != ctxt->value->floatval) {
7200 if (ctxt->value->floatval > 0)
7201 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007202 else {
7203 if (ctxt->value->floatval < 0 && f == 0)
7204 ctxt->value->floatval = xmlXPathNZERO;
7205 else
7206 ctxt->value->floatval = f;
7207 }
7208
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007209 }
Owen Taylor3473f882001-02-23 17:55:21 +00007210#endif
7211}
7212
7213/**
7214 * xmlXPathRoundFunction:
7215 * @ctxt: the XPath Parser context
7216 * @nargs: the number of arguments
7217 *
7218 * Implement the round() XPath function
7219 * number round(number)
7220 * The round function returns the number that is closest to the
7221 * argument and that is an integer. If there are two such numbers,
7222 * then the one that is even is returned.
7223 */
7224void
7225xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7226 double f;
7227
7228 CHECK_ARITY(1);
7229 CAST_TO_NUMBER;
7230 CHECK_TYPE(XPATH_NUMBER);
7231
Daniel Veillardcda96922001-08-21 10:56:31 +00007232 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7233 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7234 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007235 (ctxt->value->floatval == 0.0))
7236 return;
7237
Owen Taylor3473f882001-02-23 17:55:21 +00007238 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007239 if (ctxt->value->floatval < 0) {
7240 if (ctxt->value->floatval < f - 0.5)
7241 ctxt->value->floatval = f - 1;
7242 else
7243 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007244 if (ctxt->value->floatval == 0)
7245 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007246 } else {
7247 if (ctxt->value->floatval < f + 0.5)
7248 ctxt->value->floatval = f;
7249 else
7250 ctxt->value->floatval = f + 1;
7251 }
Owen Taylor3473f882001-02-23 17:55:21 +00007252}
7253
7254/************************************************************************
7255 * *
7256 * The Parser *
7257 * *
7258 ************************************************************************/
7259
7260/*
William M. Brack08171912003-12-29 02:52:11 +00007261 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007262 * implementation.
7263 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007264static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007265static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007266static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007267static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007268static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7269 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007270
7271/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007272 * xmlXPathCurrentChar:
7273 * @ctxt: the XPath parser context
7274 * @cur: pointer to the beginning of the char
7275 * @len: pointer to the length of the char read
7276 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007277 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007278 * bytes in the input buffer.
7279 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007280 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007281 */
7282
7283static int
7284xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7285 unsigned char c;
7286 unsigned int val;
7287 const xmlChar *cur;
7288
7289 if (ctxt == NULL)
7290 return(0);
7291 cur = ctxt->cur;
7292
7293 /*
7294 * We are supposed to handle UTF8, check it's valid
7295 * From rfc2044: encoding of the Unicode values on UTF-8:
7296 *
7297 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7298 * 0000 0000-0000 007F 0xxxxxxx
7299 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7300 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7301 *
7302 * Check for the 0x110000 limit too
7303 */
7304 c = *cur;
7305 if (c & 0x80) {
7306 if ((cur[1] & 0xc0) != 0x80)
7307 goto encoding_error;
7308 if ((c & 0xe0) == 0xe0) {
7309
7310 if ((cur[2] & 0xc0) != 0x80)
7311 goto encoding_error;
7312 if ((c & 0xf0) == 0xf0) {
7313 if (((c & 0xf8) != 0xf0) ||
7314 ((cur[3] & 0xc0) != 0x80))
7315 goto encoding_error;
7316 /* 4-byte code */
7317 *len = 4;
7318 val = (cur[0] & 0x7) << 18;
7319 val |= (cur[1] & 0x3f) << 12;
7320 val |= (cur[2] & 0x3f) << 6;
7321 val |= cur[3] & 0x3f;
7322 } else {
7323 /* 3-byte code */
7324 *len = 3;
7325 val = (cur[0] & 0xf) << 12;
7326 val |= (cur[1] & 0x3f) << 6;
7327 val |= cur[2] & 0x3f;
7328 }
7329 } else {
7330 /* 2-byte code */
7331 *len = 2;
7332 val = (cur[0] & 0x1f) << 6;
7333 val |= cur[1] & 0x3f;
7334 }
7335 if (!IS_CHAR(val)) {
7336 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7337 }
7338 return(val);
7339 } else {
7340 /* 1-byte code */
7341 *len = 1;
7342 return((int) *cur);
7343 }
7344encoding_error:
7345 /*
William M. Brack08171912003-12-29 02:52:11 +00007346 * If we detect an UTF8 error that probably means that the
7347 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007348 * declaration header. Report the error and switch the encoding
7349 * to ISO-Latin-1 (if you don't like this policy, just declare the
7350 * encoding !)
7351 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007352 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007353 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007354}
7355
7356/**
Owen Taylor3473f882001-02-23 17:55:21 +00007357 * xmlXPathParseNCName:
7358 * @ctxt: the XPath Parser context
7359 *
7360 * parse an XML namespace non qualified name.
7361 *
7362 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7363 *
7364 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7365 * CombiningChar | Extender
7366 *
7367 * Returns the namespace name or NULL
7368 */
7369
7370xmlChar *
7371xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007372 const xmlChar *in;
7373 xmlChar *ret;
7374 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007375
Daniel Veillarda82b1822004-11-08 16:24:57 +00007376 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00007377 /*
7378 * Accelerator for simple ASCII names
7379 */
7380 in = ctxt->cur;
7381 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7382 ((*in >= 0x41) && (*in <= 0x5A)) ||
7383 (*in == '_')) {
7384 in++;
7385 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7386 ((*in >= 0x41) && (*in <= 0x5A)) ||
7387 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007388 (*in == '_') || (*in == '.') ||
7389 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007390 in++;
7391 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7392 (*in == '[') || (*in == ']') || (*in == ':') ||
7393 (*in == '@') || (*in == '*')) {
7394 count = in - ctxt->cur;
7395 if (count == 0)
7396 return(NULL);
7397 ret = xmlStrndup(ctxt->cur, count);
7398 ctxt->cur = in;
7399 return(ret);
7400 }
7401 }
7402 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007403}
7404
Daniel Veillard2156a562001-04-28 12:24:34 +00007405
Owen Taylor3473f882001-02-23 17:55:21 +00007406/**
7407 * xmlXPathParseQName:
7408 * @ctxt: the XPath Parser context
7409 * @prefix: a xmlChar **
7410 *
7411 * parse an XML qualified name
7412 *
7413 * [NS 5] QName ::= (Prefix ':')? LocalPart
7414 *
7415 * [NS 6] Prefix ::= NCName
7416 *
7417 * [NS 7] LocalPart ::= NCName
7418 *
7419 * Returns the function returns the local part, and prefix is updated
7420 * to get the Prefix if any.
7421 */
7422
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007423static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007424xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7425 xmlChar *ret = NULL;
7426
7427 *prefix = NULL;
7428 ret = xmlXPathParseNCName(ctxt);
7429 if (CUR == ':') {
7430 *prefix = ret;
7431 NEXT;
7432 ret = xmlXPathParseNCName(ctxt);
7433 }
7434 return(ret);
7435}
7436
7437/**
7438 * xmlXPathParseName:
7439 * @ctxt: the XPath Parser context
7440 *
7441 * parse an XML name
7442 *
7443 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7444 * CombiningChar | Extender
7445 *
7446 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7447 *
7448 * Returns the namespace name or NULL
7449 */
7450
7451xmlChar *
7452xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007453 const xmlChar *in;
7454 xmlChar *ret;
7455 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007456
Daniel Veillarda82b1822004-11-08 16:24:57 +00007457 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007458 /*
7459 * Accelerator for simple ASCII names
7460 */
7461 in = ctxt->cur;
7462 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7463 ((*in >= 0x41) && (*in <= 0x5A)) ||
7464 (*in == '_') || (*in == ':')) {
7465 in++;
7466 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7467 ((*in >= 0x41) && (*in <= 0x5A)) ||
7468 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007469 (*in == '_') || (*in == '-') ||
7470 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007471 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007472 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007473 count = in - ctxt->cur;
7474 ret = xmlStrndup(ctxt->cur, count);
7475 ctxt->cur = in;
7476 return(ret);
7477 }
7478 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007479 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007480}
7481
Daniel Veillard61d80a22001-04-27 17:13:01 +00007482static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007483xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007484 xmlChar buf[XML_MAX_NAMELEN + 5];
7485 int len = 0, l;
7486 int c;
7487
7488 /*
7489 * Handler for more complex cases
7490 */
7491 c = CUR_CHAR(l);
7492 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007493 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7494 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007495 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007496 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007497 return(NULL);
7498 }
7499
7500 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7501 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7502 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007503 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007504 (IS_COMBINING(c)) ||
7505 (IS_EXTENDER(c)))) {
7506 COPY_BUF(l,buf,len,c);
7507 NEXTL(l);
7508 c = CUR_CHAR(l);
7509 if (len >= XML_MAX_NAMELEN) {
7510 /*
7511 * Okay someone managed to make a huge name, so he's ready to pay
7512 * for the processing speed.
7513 */
7514 xmlChar *buffer;
7515 int max = len * 2;
7516
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007517 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007518 if (buffer == NULL) {
7519 XP_ERROR0(XPATH_MEMORY_ERROR);
7520 }
7521 memcpy(buffer, buf, len);
7522 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7523 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007524 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007525 (IS_COMBINING(c)) ||
7526 (IS_EXTENDER(c))) {
7527 if (len + 10 > max) {
7528 max *= 2;
7529 buffer = (xmlChar *) xmlRealloc(buffer,
7530 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007531 if (buffer == NULL) {
7532 XP_ERROR0(XPATH_MEMORY_ERROR);
7533 }
7534 }
7535 COPY_BUF(l,buffer,len,c);
7536 NEXTL(l);
7537 c = CUR_CHAR(l);
7538 }
7539 buffer[len] = 0;
7540 return(buffer);
7541 }
7542 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007543 if (len == 0)
7544 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007545 return(xmlStrndup(buf, len));
7546}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007547
7548#define MAX_FRAC 20
7549
William M. Brack372a4452004-02-17 13:09:23 +00007550/*
7551 * These are used as divisors for the fractional part of a number.
7552 * Since the table includes 1.0 (representing '0' fractional digits),
7553 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
7554 */
7555static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007556 1.0, 10.0, 100.0, 1000.0, 10000.0,
7557 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7558 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7559 100000000000000.0,
7560 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00007561 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00007562};
7563
Owen Taylor3473f882001-02-23 17:55:21 +00007564/**
7565 * xmlXPathStringEvalNumber:
7566 * @str: A string to scan
7567 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007568 * [30a] Float ::= Number ('e' Digits?)?
7569 *
Owen Taylor3473f882001-02-23 17:55:21 +00007570 * [30] Number ::= Digits ('.' Digits?)?
7571 * | '.' Digits
7572 * [31] Digits ::= [0-9]+
7573 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007574 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007575 * In complement of the Number expression, this function also handles
7576 * negative values : '-' Number.
7577 *
7578 * Returns the double value.
7579 */
7580double
7581xmlXPathStringEvalNumber(const xmlChar *str) {
7582 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007583 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007584 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007585 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007586 int exponent = 0;
7587 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007588#ifdef __GNUC__
7589 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007590 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007591#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007592 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007593 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007594 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7595 return(xmlXPathNAN);
7596 }
7597 if (*cur == '-') {
7598 isneg = 1;
7599 cur++;
7600 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007601
7602#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007603 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007604 * tmp/temp is a workaround against a gcc compiler bug
7605 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007606 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007607 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007608 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007609 ret = ret * 10;
7610 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007611 ok = 1;
7612 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007613 temp = (double) tmp;
7614 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007615 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007616#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007617 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007618 while ((*cur >= '0') && (*cur <= '9')) {
7619 ret = ret * 10 + (*cur - '0');
7620 ok = 1;
7621 cur++;
7622 }
7623#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007624
Owen Taylor3473f882001-02-23 17:55:21 +00007625 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007626 int v, frac = 0;
7627 double fraction = 0;
7628
Owen Taylor3473f882001-02-23 17:55:21 +00007629 cur++;
7630 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7631 return(xmlXPathNAN);
7632 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007633 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7634 v = (*cur - '0');
7635 fraction = fraction * 10 + v;
7636 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007637 cur++;
7638 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007639 fraction /= my_pow10[frac];
7640 ret = ret + fraction;
7641 while ((*cur >= '0') && (*cur <= '9'))
7642 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007643 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007644 if ((*cur == 'e') || (*cur == 'E')) {
7645 cur++;
7646 if (*cur == '-') {
7647 is_exponent_negative = 1;
7648 cur++;
William M. Brack99127052004-05-24 02:52:28 +00007649 } else if (*cur == '+') {
7650 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007651 }
7652 while ((*cur >= '0') && (*cur <= '9')) {
7653 exponent = exponent * 10 + (*cur - '0');
7654 cur++;
7655 }
7656 }
William M. Brack76e95df2003-10-18 16:20:14 +00007657 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007658 if (*cur != 0) return(xmlXPathNAN);
7659 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007660 if (is_exponent_negative) exponent = -exponent;
7661 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007662 return(ret);
7663}
7664
7665/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007666 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007667 * @ctxt: the XPath Parser context
7668 *
7669 * [30] Number ::= Digits ('.' Digits?)?
7670 * | '.' Digits
7671 * [31] Digits ::= [0-9]+
7672 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007673 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007674 *
7675 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007676static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007677xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7678{
Owen Taylor3473f882001-02-23 17:55:21 +00007679 double ret = 0.0;
7680 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007681 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007682 int exponent = 0;
7683 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007684#ifdef __GNUC__
7685 unsigned long tmp = 0;
7686 double temp;
7687#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007688
7689 CHECK_ERROR;
7690 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7691 XP_ERROR(XPATH_NUMBER_ERROR);
7692 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007693#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007694 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007695 * tmp/temp is a workaround against a gcc compiler bug
7696 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007697 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007698 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007699 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007700 ret = ret * 10;
7701 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007702 ok = 1;
7703 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007704 temp = (double) tmp;
7705 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007706 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007707#else
7708 ret = 0;
7709 while ((CUR >= '0') && (CUR <= '9')) {
7710 ret = ret * 10 + (CUR - '0');
7711 ok = 1;
7712 NEXT;
7713 }
7714#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007715 if (CUR == '.') {
7716 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007717 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7718 XP_ERROR(XPATH_NUMBER_ERROR);
7719 }
7720 while ((CUR >= '0') && (CUR <= '9')) {
7721 mult /= 10;
7722 ret = ret + (CUR - '0') * mult;
7723 NEXT;
7724 }
Owen Taylor3473f882001-02-23 17:55:21 +00007725 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007726 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007727 NEXT;
7728 if (CUR == '-') {
7729 is_exponent_negative = 1;
7730 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00007731 } else if (CUR == '+') {
7732 NEXT;
7733 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007734 while ((CUR >= '0') && (CUR <= '9')) {
7735 exponent = exponent * 10 + (CUR - '0');
7736 NEXT;
7737 }
7738 if (is_exponent_negative)
7739 exponent = -exponent;
7740 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007741 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007742 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007743 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007744}
7745
7746/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007747 * xmlXPathParseLiteral:
7748 * @ctxt: the XPath Parser context
7749 *
7750 * Parse a Literal
7751 *
7752 * [29] Literal ::= '"' [^"]* '"'
7753 * | "'" [^']* "'"
7754 *
7755 * Returns the value found or NULL in case of error
7756 */
7757static xmlChar *
7758xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7759 const xmlChar *q;
7760 xmlChar *ret = NULL;
7761
7762 if (CUR == '"') {
7763 NEXT;
7764 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007765 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007766 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007767 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007768 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7769 } else {
7770 ret = xmlStrndup(q, CUR_PTR - q);
7771 NEXT;
7772 }
7773 } else if (CUR == '\'') {
7774 NEXT;
7775 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007776 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007777 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007778 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007779 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7780 } else {
7781 ret = xmlStrndup(q, CUR_PTR - q);
7782 NEXT;
7783 }
7784 } else {
7785 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7786 }
7787 return(ret);
7788}
7789
7790/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007791 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007792 * @ctxt: the XPath Parser context
7793 *
7794 * Parse a Literal and push it on the stack.
7795 *
7796 * [29] Literal ::= '"' [^"]* '"'
7797 * | "'" [^']* "'"
7798 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007799 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007800 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007801static void
7802xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007803 const xmlChar *q;
7804 xmlChar *ret = NULL;
7805
7806 if (CUR == '"') {
7807 NEXT;
7808 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007809 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007810 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007811 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007812 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7813 } else {
7814 ret = xmlStrndup(q, CUR_PTR - q);
7815 NEXT;
7816 }
7817 } else if (CUR == '\'') {
7818 NEXT;
7819 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007820 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007821 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007822 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007823 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7824 } else {
7825 ret = xmlStrndup(q, CUR_PTR - q);
7826 NEXT;
7827 }
7828 } else {
7829 XP_ERROR(XPATH_START_LITERAL_ERROR);
7830 }
7831 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007832 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7833 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007834 xmlFree(ret);
7835}
7836
7837/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007838 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007839 * @ctxt: the XPath Parser context
7840 *
7841 * Parse a VariableReference, evaluate it and push it on the stack.
7842 *
7843 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00007844 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00007845 * of any of the types that are possible for the value of an expression,
7846 * and may also be of additional types not specified here.
7847 *
7848 * Early evaluation is possible since:
7849 * The variable bindings [...] used to evaluate a subexpression are
7850 * always the same as those used to evaluate the containing expression.
7851 *
7852 * [36] VariableReference ::= '$' QName
7853 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007854static void
7855xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007856 xmlChar *name;
7857 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007858
7859 SKIP_BLANKS;
7860 if (CUR != '$') {
7861 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7862 }
7863 NEXT;
7864 name = xmlXPathParseQName(ctxt, &prefix);
7865 if (name == NULL) {
7866 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7867 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007868 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007869 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7870 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007871 SKIP_BLANKS;
7872}
7873
7874/**
7875 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007876 * @name: a name string
7877 *
7878 * Is the name given a NodeType one.
7879 *
7880 * [38] NodeType ::= 'comment'
7881 * | 'text'
7882 * | 'processing-instruction'
7883 * | 'node'
7884 *
7885 * Returns 1 if true 0 otherwise
7886 */
7887int
7888xmlXPathIsNodeType(const xmlChar *name) {
7889 if (name == NULL)
7890 return(0);
7891
Daniel Veillard1971ee22002-01-31 20:29:19 +00007892 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007893 return(1);
7894 if (xmlStrEqual(name, BAD_CAST "text"))
7895 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007896 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007897 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007898 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007899 return(1);
7900 return(0);
7901}
7902
7903/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007904 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007905 * @ctxt: the XPath Parser context
7906 *
7907 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7908 * [17] Argument ::= Expr
7909 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007910 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007911 * pushed on the stack
7912 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007913static void
7914xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007915 xmlChar *name;
7916 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007917 int nbargs = 0;
7918
7919 name = xmlXPathParseQName(ctxt, &prefix);
7920 if (name == NULL) {
7921 XP_ERROR(XPATH_EXPR_ERROR);
7922 }
7923 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007924#ifdef DEBUG_EXPR
7925 if (prefix == NULL)
7926 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7927 name);
7928 else
7929 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7930 prefix, name);
7931#endif
7932
Owen Taylor3473f882001-02-23 17:55:21 +00007933 if (CUR != '(') {
7934 XP_ERROR(XPATH_EXPR_ERROR);
7935 }
7936 NEXT;
7937 SKIP_BLANKS;
7938
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007939 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007940 if (CUR != ')') {
7941 while (CUR != 0) {
7942 int op1 = ctxt->comp->last;
7943 ctxt->comp->last = -1;
7944 xmlXPathCompileExpr(ctxt);
7945 CHECK_ERROR;
7946 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7947 nbargs++;
7948 if (CUR == ')') break;
7949 if (CUR != ',') {
7950 XP_ERROR(XPATH_EXPR_ERROR);
7951 }
7952 NEXT;
7953 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007954 }
Owen Taylor3473f882001-02-23 17:55:21 +00007955 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007956 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7957 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007958 NEXT;
7959 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007960}
7961
7962/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007963 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007964 * @ctxt: the XPath Parser context
7965 *
7966 * [15] PrimaryExpr ::= VariableReference
7967 * | '(' Expr ')'
7968 * | Literal
7969 * | Number
7970 * | FunctionCall
7971 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007972 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007973 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007974static void
7975xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007976 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007977 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007978 else if (CUR == '(') {
7979 NEXT;
7980 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007981 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007982 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007983 if (CUR != ')') {
7984 XP_ERROR(XPATH_EXPR_ERROR);
7985 }
7986 NEXT;
7987 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00007988 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007989 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007990 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007991 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007992 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007993 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007994 }
7995 SKIP_BLANKS;
7996}
7997
7998/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007999 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008000 * @ctxt: the XPath Parser context
8001 *
8002 * [20] FilterExpr ::= PrimaryExpr
8003 * | FilterExpr Predicate
8004 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008005 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008006 * Square brackets are used to filter expressions in the same way that
8007 * they are used in location paths. It is an error if the expression to
8008 * be filtered does not evaluate to a node-set. The context node list
8009 * used for evaluating the expression in square brackets is the node-set
8010 * to be filtered listed in document order.
8011 */
8012
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008013static void
8014xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8015 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008016 CHECK_ERROR;
8017 SKIP_BLANKS;
8018
8019 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008020 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00008021 SKIP_BLANKS;
8022 }
8023
8024
8025}
8026
8027/**
8028 * xmlXPathScanName:
8029 * @ctxt: the XPath Parser context
8030 *
8031 * Trickery: parse an XML name but without consuming the input flow
8032 * Needed to avoid insanity in the parser state.
8033 *
8034 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8035 * CombiningChar | Extender
8036 *
8037 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8038 *
8039 * [6] Names ::= Name (S Name)*
8040 *
8041 * Returns the Name parsed or NULL
8042 */
8043
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008044static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00008045xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +00008046 int len = 0, l;
8047 int c;
Daniel Veillard03226812004-11-01 14:55:21 +00008048 const xmlChar *cur;
8049 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00008050
Daniel Veillard03226812004-11-01 14:55:21 +00008051 cur = ctxt->cur;
8052
8053 c = CUR_CHAR(l);
8054 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8055 (!IS_LETTER(c) && (c != '_') &&
8056 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008057 return(NULL);
8058 }
8059
Daniel Veillard03226812004-11-01 14:55:21 +00008060 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8061 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8062 (c == '.') || (c == '-') ||
8063 (c == '_') || (c == ':') ||
8064 (IS_COMBINING(c)) ||
8065 (IS_EXTENDER(c)))) {
8066 len += l;
8067 NEXTL(l);
8068 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +00008069 }
Daniel Veillard03226812004-11-01 14:55:21 +00008070 ret = xmlStrndup(cur, ctxt->cur - cur);
8071 ctxt->cur = cur;
8072 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00008073}
8074
8075/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008076 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008077 * @ctxt: the XPath Parser context
8078 *
8079 * [19] PathExpr ::= LocationPath
8080 * | FilterExpr
8081 * | FilterExpr '/' RelativeLocationPath
8082 * | FilterExpr '//' RelativeLocationPath
8083 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008084 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008085 * The / operator and // operators combine an arbitrary expression
8086 * and a relative location path. It is an error if the expression
8087 * does not evaluate to a node-set.
8088 * The / operator does composition in the same way as when / is
8089 * used in a location path. As in location paths, // is short for
8090 * /descendant-or-self::node()/.
8091 */
8092
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008093static void
8094xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008095 int lc = 1; /* Should we branch to LocationPath ? */
8096 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8097
8098 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008099 if ((CUR == '$') || (CUR == '(') ||
8100 (IS_ASCII_DIGIT(CUR)) ||
8101 (CUR == '\'') || (CUR == '"') ||
8102 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008103 lc = 0;
8104 } else if (CUR == '*') {
8105 /* relative or absolute location path */
8106 lc = 1;
8107 } else if (CUR == '/') {
8108 /* relative or absolute location path */
8109 lc = 1;
8110 } else if (CUR == '@') {
8111 /* relative abbreviated attribute location path */
8112 lc = 1;
8113 } else if (CUR == '.') {
8114 /* relative abbreviated attribute location path */
8115 lc = 1;
8116 } else {
8117 /*
8118 * Problem is finding if we have a name here whether it's:
8119 * - a nodetype
8120 * - a function call in which case it's followed by '('
8121 * - an axis in which case it's followed by ':'
8122 * - a element name
8123 * We do an a priori analysis here rather than having to
8124 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008125 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008126 * read/write/debug.
8127 */
8128 SKIP_BLANKS;
8129 name = xmlXPathScanName(ctxt);
8130 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8131#ifdef DEBUG_STEP
8132 xmlGenericError(xmlGenericErrorContext,
8133 "PathExpr: Axis\n");
8134#endif
8135 lc = 1;
8136 xmlFree(name);
8137 } else if (name != NULL) {
8138 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008139
8140
8141 while (NXT(len) != 0) {
8142 if (NXT(len) == '/') {
8143 /* element name */
8144#ifdef DEBUG_STEP
8145 xmlGenericError(xmlGenericErrorContext,
8146 "PathExpr: AbbrRelLocation\n");
8147#endif
8148 lc = 1;
8149 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008150 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008151 /* ignore blanks */
8152 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008153 } else if (NXT(len) == ':') {
8154#ifdef DEBUG_STEP
8155 xmlGenericError(xmlGenericErrorContext,
8156 "PathExpr: AbbrRelLocation\n");
8157#endif
8158 lc = 1;
8159 break;
8160 } else if ((NXT(len) == '(')) {
8161 /* Note Type or Function */
8162 if (xmlXPathIsNodeType(name)) {
8163#ifdef DEBUG_STEP
8164 xmlGenericError(xmlGenericErrorContext,
8165 "PathExpr: Type search\n");
8166#endif
8167 lc = 1;
8168 } else {
8169#ifdef DEBUG_STEP
8170 xmlGenericError(xmlGenericErrorContext,
8171 "PathExpr: function call\n");
8172#endif
8173 lc = 0;
8174 }
8175 break;
8176 } else if ((NXT(len) == '[')) {
8177 /* element name */
8178#ifdef DEBUG_STEP
8179 xmlGenericError(xmlGenericErrorContext,
8180 "PathExpr: AbbrRelLocation\n");
8181#endif
8182 lc = 1;
8183 break;
8184 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8185 (NXT(len) == '=')) {
8186 lc = 1;
8187 break;
8188 } else {
8189 lc = 1;
8190 break;
8191 }
8192 len++;
8193 }
8194 if (NXT(len) == 0) {
8195#ifdef DEBUG_STEP
8196 xmlGenericError(xmlGenericErrorContext,
8197 "PathExpr: AbbrRelLocation\n");
8198#endif
8199 /* element name */
8200 lc = 1;
8201 }
8202 xmlFree(name);
8203 } else {
William M. Brack08171912003-12-29 02:52:11 +00008204 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008205 XP_ERROR(XPATH_EXPR_ERROR);
8206 }
8207 }
8208
8209 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008210 if (CUR == '/') {
8211 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8212 } else {
8213 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008214 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008215 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008216 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008217 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008218 CHECK_ERROR;
8219 if ((CUR == '/') && (NXT(1) == '/')) {
8220 SKIP(2);
8221 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008222
8223 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8224 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8225 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8226
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008227 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008228 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008229 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008230 }
8231 }
8232 SKIP_BLANKS;
8233}
8234
8235/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008236 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008237 * @ctxt: the XPath Parser context
8238 *
8239 * [18] UnionExpr ::= PathExpr
8240 * | UnionExpr '|' PathExpr
8241 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008242 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008243 */
8244
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008245static void
8246xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8247 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008248 CHECK_ERROR;
8249 SKIP_BLANKS;
8250 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008251 int op1 = ctxt->comp->last;
8252 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008253
8254 NEXT;
8255 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008256 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008257
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008258 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8259
Owen Taylor3473f882001-02-23 17:55:21 +00008260 SKIP_BLANKS;
8261 }
Owen Taylor3473f882001-02-23 17:55:21 +00008262}
8263
8264/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008265 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008266 * @ctxt: the XPath Parser context
8267 *
8268 * [27] UnaryExpr ::= UnionExpr
8269 * | '-' UnaryExpr
8270 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008271 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008272 */
8273
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008274static void
8275xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008276 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008277 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008278
8279 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008280 while (CUR == '-') {
8281 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008282 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008283 NEXT;
8284 SKIP_BLANKS;
8285 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008286
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008287 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008288 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008289 if (found) {
8290 if (minus)
8291 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8292 else
8293 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008294 }
8295}
8296
8297/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008298 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008299 * @ctxt: the XPath Parser context
8300 *
8301 * [26] MultiplicativeExpr ::= UnaryExpr
8302 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8303 * | MultiplicativeExpr 'div' UnaryExpr
8304 * | MultiplicativeExpr 'mod' UnaryExpr
8305 * [34] MultiplyOperator ::= '*'
8306 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008307 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008308 */
8309
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008310static void
8311xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8312 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008313 CHECK_ERROR;
8314 SKIP_BLANKS;
8315 while ((CUR == '*') ||
8316 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8317 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8318 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008319 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008320
8321 if (CUR == '*') {
8322 op = 0;
8323 NEXT;
8324 } else if (CUR == 'd') {
8325 op = 1;
8326 SKIP(3);
8327 } else if (CUR == 'm') {
8328 op = 2;
8329 SKIP(3);
8330 }
8331 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008332 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008333 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008334 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008335 SKIP_BLANKS;
8336 }
8337}
8338
8339/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008340 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008341 * @ctxt: the XPath Parser context
8342 *
8343 * [25] AdditiveExpr ::= MultiplicativeExpr
8344 * | AdditiveExpr '+' MultiplicativeExpr
8345 * | AdditiveExpr '-' MultiplicativeExpr
8346 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008347 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008348 */
8349
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008350static void
8351xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008352
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008353 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008354 CHECK_ERROR;
8355 SKIP_BLANKS;
8356 while ((CUR == '+') || (CUR == '-')) {
8357 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008358 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008359
8360 if (CUR == '+') plus = 1;
8361 else plus = 0;
8362 NEXT;
8363 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008364 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008365 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008366 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008367 SKIP_BLANKS;
8368 }
8369}
8370
8371/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008372 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008373 * @ctxt: the XPath Parser context
8374 *
8375 * [24] RelationalExpr ::= AdditiveExpr
8376 * | RelationalExpr '<' AdditiveExpr
8377 * | RelationalExpr '>' AdditiveExpr
8378 * | RelationalExpr '<=' AdditiveExpr
8379 * | RelationalExpr '>=' AdditiveExpr
8380 *
8381 * A <= B > C is allowed ? Answer from James, yes with
8382 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8383 * which is basically what got implemented.
8384 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008385 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008386 * on the stack
8387 */
8388
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008389static void
8390xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8391 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008392 CHECK_ERROR;
8393 SKIP_BLANKS;
8394 while ((CUR == '<') ||
8395 (CUR == '>') ||
8396 ((CUR == '<') && (NXT(1) == '=')) ||
8397 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008398 int inf, strict;
8399 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008400
8401 if (CUR == '<') inf = 1;
8402 else inf = 0;
8403 if (NXT(1) == '=') strict = 0;
8404 else strict = 1;
8405 NEXT;
8406 if (!strict) NEXT;
8407 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008408 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008409 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008410 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008411 SKIP_BLANKS;
8412 }
8413}
8414
8415/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008416 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008417 * @ctxt: the XPath Parser context
8418 *
8419 * [23] EqualityExpr ::= RelationalExpr
8420 * | EqualityExpr '=' RelationalExpr
8421 * | EqualityExpr '!=' RelationalExpr
8422 *
8423 * A != B != C is allowed ? Answer from James, yes with
8424 * (RelationalExpr = RelationalExpr) = RelationalExpr
8425 * (RelationalExpr != RelationalExpr) != RelationalExpr
8426 * which is basically what got implemented.
8427 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008428 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008429 *
8430 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008431static void
8432xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8433 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008434 CHECK_ERROR;
8435 SKIP_BLANKS;
8436 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008437 int eq;
8438 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008439
8440 if (CUR == '=') eq = 1;
8441 else eq = 0;
8442 NEXT;
8443 if (!eq) NEXT;
8444 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008445 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008446 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008447 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008448 SKIP_BLANKS;
8449 }
8450}
8451
8452/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008453 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008454 * @ctxt: the XPath Parser context
8455 *
8456 * [22] AndExpr ::= EqualityExpr
8457 * | AndExpr 'and' EqualityExpr
8458 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008459 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008460 *
8461 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008462static void
8463xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8464 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008465 CHECK_ERROR;
8466 SKIP_BLANKS;
8467 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008468 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008469 SKIP(3);
8470 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008471 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008472 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008473 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008474 SKIP_BLANKS;
8475 }
8476}
8477
8478/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008479 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008480 * @ctxt: the XPath Parser context
8481 *
8482 * [14] Expr ::= OrExpr
8483 * [21] OrExpr ::= AndExpr
8484 * | OrExpr 'or' AndExpr
8485 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008486 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008487 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008488static void
8489xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8490 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008491 CHECK_ERROR;
8492 SKIP_BLANKS;
8493 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008494 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008495 SKIP(2);
8496 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008497 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008498 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008499 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8500 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008501 SKIP_BLANKS;
8502 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008503 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8504 /* more ops could be optimized too */
8505 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8506 }
Owen Taylor3473f882001-02-23 17:55:21 +00008507}
8508
8509/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008510 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008511 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008512 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008513 *
8514 * [8] Predicate ::= '[' PredicateExpr ']'
8515 * [9] PredicateExpr ::= Expr
8516 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008517 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008518 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008519static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008520xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008521 int op1 = ctxt->comp->last;
8522
8523 SKIP_BLANKS;
8524 if (CUR != '[') {
8525 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8526 }
8527 NEXT;
8528 SKIP_BLANKS;
8529
8530 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008531 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008532 CHECK_ERROR;
8533
8534 if (CUR != ']') {
8535 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8536 }
8537
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008538 if (filter)
8539 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8540 else
8541 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008542
8543 NEXT;
8544 SKIP_BLANKS;
8545}
8546
8547/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008548 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008549 * @ctxt: the XPath Parser context
8550 * @test: pointer to a xmlXPathTestVal
8551 * @type: pointer to a xmlXPathTypeVal
8552 * @prefix: placeholder for a possible name prefix
8553 *
8554 * [7] NodeTest ::= NameTest
8555 * | NodeType '(' ')'
8556 * | 'processing-instruction' '(' Literal ')'
8557 *
8558 * [37] NameTest ::= '*'
8559 * | NCName ':' '*'
8560 * | QName
8561 * [38] NodeType ::= 'comment'
8562 * | 'text'
8563 * | 'processing-instruction'
8564 * | 'node'
8565 *
William M. Brack08171912003-12-29 02:52:11 +00008566 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00008567 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008568static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008569xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8570 xmlXPathTypeVal *type, const xmlChar **prefix,
8571 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008572 int blanks;
8573
8574 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8575 STRANGE;
8576 return(NULL);
8577 }
William M. Brack78637da2003-07-31 14:47:38 +00008578 *type = (xmlXPathTypeVal) 0;
8579 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008580 *prefix = NULL;
8581 SKIP_BLANKS;
8582
8583 if ((name == NULL) && (CUR == '*')) {
8584 /*
8585 * All elements
8586 */
8587 NEXT;
8588 *test = NODE_TEST_ALL;
8589 return(NULL);
8590 }
8591
8592 if (name == NULL)
8593 name = xmlXPathParseNCName(ctxt);
8594 if (name == NULL) {
8595 XP_ERROR0(XPATH_EXPR_ERROR);
8596 }
8597
William M. Brack76e95df2003-10-18 16:20:14 +00008598 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008599 SKIP_BLANKS;
8600 if (CUR == '(') {
8601 NEXT;
8602 /*
8603 * NodeType or PI search
8604 */
8605 if (xmlStrEqual(name, BAD_CAST "comment"))
8606 *type = NODE_TYPE_COMMENT;
8607 else if (xmlStrEqual(name, BAD_CAST "node"))
8608 *type = NODE_TYPE_NODE;
8609 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8610 *type = NODE_TYPE_PI;
8611 else if (xmlStrEqual(name, BAD_CAST "text"))
8612 *type = NODE_TYPE_TEXT;
8613 else {
8614 if (name != NULL)
8615 xmlFree(name);
8616 XP_ERROR0(XPATH_EXPR_ERROR);
8617 }
8618
8619 *test = NODE_TEST_TYPE;
8620
8621 SKIP_BLANKS;
8622 if (*type == NODE_TYPE_PI) {
8623 /*
8624 * Specific case: search a PI by name.
8625 */
Owen Taylor3473f882001-02-23 17:55:21 +00008626 if (name != NULL)
8627 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008628 name = NULL;
8629 if (CUR != ')') {
8630 name = xmlXPathParseLiteral(ctxt);
8631 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008632 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008633 SKIP_BLANKS;
8634 }
Owen Taylor3473f882001-02-23 17:55:21 +00008635 }
8636 if (CUR != ')') {
8637 if (name != NULL)
8638 xmlFree(name);
8639 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8640 }
8641 NEXT;
8642 return(name);
8643 }
8644 *test = NODE_TEST_NAME;
8645 if ((!blanks) && (CUR == ':')) {
8646 NEXT;
8647
8648 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008649 * Since currently the parser context don't have a
8650 * namespace list associated:
8651 * The namespace name for this prefix can be computed
8652 * only at evaluation time. The compilation is done
8653 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008654 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008655#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008656 *prefix = xmlXPathNsLookup(ctxt->context, name);
8657 if (name != NULL)
8658 xmlFree(name);
8659 if (*prefix == NULL) {
8660 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8661 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008662#else
8663 *prefix = name;
8664#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008665
8666 if (CUR == '*') {
8667 /*
8668 * All elements
8669 */
8670 NEXT;
8671 *test = NODE_TEST_ALL;
8672 return(NULL);
8673 }
8674
8675 name = xmlXPathParseNCName(ctxt);
8676 if (name == NULL) {
8677 XP_ERROR0(XPATH_EXPR_ERROR);
8678 }
8679 }
8680 return(name);
8681}
8682
8683/**
8684 * xmlXPathIsAxisName:
8685 * @name: a preparsed name token
8686 *
8687 * [6] AxisName ::= 'ancestor'
8688 * | 'ancestor-or-self'
8689 * | 'attribute'
8690 * | 'child'
8691 * | 'descendant'
8692 * | 'descendant-or-self'
8693 * | 'following'
8694 * | 'following-sibling'
8695 * | 'namespace'
8696 * | 'parent'
8697 * | 'preceding'
8698 * | 'preceding-sibling'
8699 * | 'self'
8700 *
8701 * Returns the axis or 0
8702 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008703static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008704xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008705 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008706 switch (name[0]) {
8707 case 'a':
8708 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8709 ret = AXIS_ANCESTOR;
8710 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8711 ret = AXIS_ANCESTOR_OR_SELF;
8712 if (xmlStrEqual(name, BAD_CAST "attribute"))
8713 ret = AXIS_ATTRIBUTE;
8714 break;
8715 case 'c':
8716 if (xmlStrEqual(name, BAD_CAST "child"))
8717 ret = AXIS_CHILD;
8718 break;
8719 case 'd':
8720 if (xmlStrEqual(name, BAD_CAST "descendant"))
8721 ret = AXIS_DESCENDANT;
8722 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8723 ret = AXIS_DESCENDANT_OR_SELF;
8724 break;
8725 case 'f':
8726 if (xmlStrEqual(name, BAD_CAST "following"))
8727 ret = AXIS_FOLLOWING;
8728 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8729 ret = AXIS_FOLLOWING_SIBLING;
8730 break;
8731 case 'n':
8732 if (xmlStrEqual(name, BAD_CAST "namespace"))
8733 ret = AXIS_NAMESPACE;
8734 break;
8735 case 'p':
8736 if (xmlStrEqual(name, BAD_CAST "parent"))
8737 ret = AXIS_PARENT;
8738 if (xmlStrEqual(name, BAD_CAST "preceding"))
8739 ret = AXIS_PRECEDING;
8740 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8741 ret = AXIS_PRECEDING_SIBLING;
8742 break;
8743 case 's':
8744 if (xmlStrEqual(name, BAD_CAST "self"))
8745 ret = AXIS_SELF;
8746 break;
8747 }
8748 return(ret);
8749}
8750
8751/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008752 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008753 * @ctxt: the XPath Parser context
8754 *
8755 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8756 * | AbbreviatedStep
8757 *
8758 * [12] AbbreviatedStep ::= '.' | '..'
8759 *
8760 * [5] AxisSpecifier ::= AxisName '::'
8761 * | AbbreviatedAxisSpecifier
8762 *
8763 * [13] AbbreviatedAxisSpecifier ::= '@'?
8764 *
8765 * Modified for XPtr range support as:
8766 *
8767 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8768 * | AbbreviatedStep
8769 * | 'range-to' '(' Expr ')' Predicate*
8770 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008771 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008772 * A location step of . is short for self::node(). This is
8773 * particularly useful in conjunction with //. For example, the
8774 * location path .//para is short for
8775 * self::node()/descendant-or-self::node()/child::para
8776 * and so will select all para descendant elements of the context
8777 * node.
8778 * Similarly, a location step of .. is short for parent::node().
8779 * For example, ../title is short for parent::node()/child::title
8780 * and so will select the title children of the parent of the context
8781 * node.
8782 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008783static void
8784xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008785#ifdef LIBXML_XPTR_ENABLED
8786 int rangeto = 0;
8787 int op2 = -1;
8788#endif
8789
Owen Taylor3473f882001-02-23 17:55:21 +00008790 SKIP_BLANKS;
8791 if ((CUR == '.') && (NXT(1) == '.')) {
8792 SKIP(2);
8793 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008794 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8795 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008796 } else if (CUR == '.') {
8797 NEXT;
8798 SKIP_BLANKS;
8799 } else {
8800 xmlChar *name = NULL;
8801 const xmlChar *prefix = NULL;
8802 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008803 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008804 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008805 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008806
8807 /*
8808 * The modification needed for XPointer change to the production
8809 */
8810#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008811 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008812 name = xmlXPathParseNCName(ctxt);
8813 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008814 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008815 xmlFree(name);
8816 SKIP_BLANKS;
8817 if (CUR != '(') {
8818 XP_ERROR(XPATH_EXPR_ERROR);
8819 }
8820 NEXT;
8821 SKIP_BLANKS;
8822
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008823 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008824 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008825 CHECK_ERROR;
8826
8827 SKIP_BLANKS;
8828 if (CUR != ')') {
8829 XP_ERROR(XPATH_EXPR_ERROR);
8830 }
8831 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008832 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008833 goto eval_predicates;
8834 }
8835 }
8836#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008837 if (CUR == '*') {
8838 axis = AXIS_CHILD;
8839 } else {
8840 if (name == NULL)
8841 name = xmlXPathParseNCName(ctxt);
8842 if (name != NULL) {
8843 axis = xmlXPathIsAxisName(name);
8844 if (axis != 0) {
8845 SKIP_BLANKS;
8846 if ((CUR == ':') && (NXT(1) == ':')) {
8847 SKIP(2);
8848 xmlFree(name);
8849 name = NULL;
8850 } else {
8851 /* an element name can conflict with an axis one :-\ */
8852 axis = AXIS_CHILD;
8853 }
Owen Taylor3473f882001-02-23 17:55:21 +00008854 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008855 axis = AXIS_CHILD;
8856 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008857 } else if (CUR == '@') {
8858 NEXT;
8859 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008860 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008861 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008862 }
Owen Taylor3473f882001-02-23 17:55:21 +00008863 }
8864
8865 CHECK_ERROR;
8866
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008867 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008868 if (test == 0)
8869 return;
8870
8871#ifdef DEBUG_STEP
8872 xmlGenericError(xmlGenericErrorContext,
8873 "Basis : computing new set\n");
8874#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008875
Owen Taylor3473f882001-02-23 17:55:21 +00008876#ifdef DEBUG_STEP
8877 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008878 if (ctxt->value == NULL)
8879 xmlGenericError(xmlGenericErrorContext, "no value\n");
8880 else if (ctxt->value->nodesetval == NULL)
8881 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8882 else
8883 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008884#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008885
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008886#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008887eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008888#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008889 op1 = ctxt->comp->last;
8890 ctxt->comp->last = -1;
8891
Owen Taylor3473f882001-02-23 17:55:21 +00008892 SKIP_BLANKS;
8893 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008894 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008895 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008896
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008897#ifdef LIBXML_XPTR_ENABLED
8898 if (rangeto) {
8899 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8900 } else
8901#endif
8902 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8903 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008904
Owen Taylor3473f882001-02-23 17:55:21 +00008905 }
8906#ifdef DEBUG_STEP
8907 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008908 if (ctxt->value == NULL)
8909 xmlGenericError(xmlGenericErrorContext, "no value\n");
8910 else if (ctxt->value->nodesetval == NULL)
8911 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8912 else
8913 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8914 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008915#endif
8916}
8917
8918/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008919 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008920 * @ctxt: the XPath Parser context
8921 *
8922 * [3] RelativeLocationPath ::= Step
8923 * | RelativeLocationPath '/' Step
8924 * | AbbreviatedRelativeLocationPath
8925 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8926 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008927 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008928 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008929static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008930xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008931(xmlXPathParserContextPtr ctxt) {
8932 SKIP_BLANKS;
8933 if ((CUR == '/') && (NXT(1) == '/')) {
8934 SKIP(2);
8935 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008936 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8937 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008938 } else if (CUR == '/') {
8939 NEXT;
8940 SKIP_BLANKS;
8941 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008942 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008943 SKIP_BLANKS;
8944 while (CUR == '/') {
8945 if ((CUR == '/') && (NXT(1) == '/')) {
8946 SKIP(2);
8947 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008948 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008949 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008950 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008951 } else if (CUR == '/') {
8952 NEXT;
8953 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008954 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008955 }
8956 SKIP_BLANKS;
8957 }
8958}
8959
8960/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008961 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008962 * @ctxt: the XPath Parser context
8963 *
8964 * [1] LocationPath ::= RelativeLocationPath
8965 * | AbsoluteLocationPath
8966 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8967 * | AbbreviatedAbsoluteLocationPath
8968 * [10] AbbreviatedAbsoluteLocationPath ::=
8969 * '//' RelativeLocationPath
8970 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008971 * Compile a location path
8972 *
Owen Taylor3473f882001-02-23 17:55:21 +00008973 * // is short for /descendant-or-self::node()/. For example,
8974 * //para is short for /descendant-or-self::node()/child::para and
8975 * so will select any para element in the document (even a para element
8976 * that is a document element will be selected by //para since the
8977 * document element node is a child of the root node); div//para is
8978 * short for div/descendant-or-self::node()/child::para and so will
8979 * select all para descendants of div children.
8980 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008981static void
8982xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008983 SKIP_BLANKS;
8984 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008985 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008986 } else {
8987 while (CUR == '/') {
8988 if ((CUR == '/') && (NXT(1) == '/')) {
8989 SKIP(2);
8990 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008991 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8992 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008993 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008994 } else if (CUR == '/') {
8995 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008996 SKIP_BLANKS;
8997 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +00008998 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00008999 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009000 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009001 }
9002 }
9003 }
9004}
9005
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009006/************************************************************************
9007 * *
9008 * XPath precompiled expression evaluation *
9009 * *
9010 ************************************************************************/
9011
Daniel Veillardf06307e2001-07-03 10:35:50 +00009012static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009013xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
9014
9015/**
9016 * xmlXPathNodeCollectAndTest:
9017 * @ctxt: the XPath Parser context
9018 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009019 * @first: pointer to the first element in document order
9020 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009021 *
9022 * This is the function implementing a step: based on the current list
9023 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009024 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009025 *
9026 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00009027 *
William M. Brack08171912003-12-29 02:52:11 +00009028 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009029 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009030static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009031xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009032 xmlXPathStepOpPtr op,
9033 xmlNodePtr * first, xmlNodePtr * last)
9034{
William M. Brack78637da2003-07-31 14:47:38 +00009035 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9036 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9037 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009038 const xmlChar *prefix = op->value4;
9039 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009040 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009041
9042#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009043 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009044#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009045 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009046 xmlNodeSetPtr ret, list;
9047 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009048 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00009049 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009050 xmlNodePtr cur = NULL;
9051 xmlXPathObjectPtr obj;
9052 xmlNodeSetPtr nodelist;
9053 xmlNodePtr tmp;
9054
Daniel Veillardf06307e2001-07-03 10:35:50 +00009055 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009056 obj = valuePop(ctxt);
9057 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009058 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009059 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009060 URI = xmlXPathNsLookup(ctxt->context, prefix);
9061 if (URI == NULL)
9062 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00009063 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009064#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009065 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009066#endif
9067 switch (axis) {
9068 case AXIS_ANCESTOR:
9069#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009070 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009071#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009072 first = NULL;
9073 next = xmlXPathNextAncestor;
9074 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009075 case AXIS_ANCESTOR_OR_SELF:
9076#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009077 xmlGenericError(xmlGenericErrorContext,
9078 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009079#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009080 first = NULL;
9081 next = xmlXPathNextAncestorOrSelf;
9082 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009083 case AXIS_ATTRIBUTE:
9084#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009085 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009086#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009087 first = NULL;
9088 last = NULL;
9089 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009090 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009091 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009092 case AXIS_CHILD:
9093#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009094 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009095#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009096 last = NULL;
9097 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009098 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009099 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009100 case AXIS_DESCENDANT:
9101#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009102 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009103#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009104 last = NULL;
9105 next = xmlXPathNextDescendant;
9106 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009107 case AXIS_DESCENDANT_OR_SELF:
9108#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009109 xmlGenericError(xmlGenericErrorContext,
9110 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009111#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009112 last = NULL;
9113 next = xmlXPathNextDescendantOrSelf;
9114 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009115 case AXIS_FOLLOWING:
9116#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009117 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009118#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009119 last = NULL;
9120 next = xmlXPathNextFollowing;
9121 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009122 case AXIS_FOLLOWING_SIBLING:
9123#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009124 xmlGenericError(xmlGenericErrorContext,
9125 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009126#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009127 last = NULL;
9128 next = xmlXPathNextFollowingSibling;
9129 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009130 case AXIS_NAMESPACE:
9131#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009132 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009133#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009134 first = NULL;
9135 last = NULL;
9136 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009137 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009138 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009139 case AXIS_PARENT:
9140#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009141 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009142#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009143 first = NULL;
9144 next = xmlXPathNextParent;
9145 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009146 case AXIS_PRECEDING:
9147#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009148 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009149#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009150 first = NULL;
9151 next = xmlXPathNextPrecedingInternal;
9152 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009153 case AXIS_PRECEDING_SIBLING:
9154#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009155 xmlGenericError(xmlGenericErrorContext,
9156 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009157#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009158 first = NULL;
9159 next = xmlXPathNextPrecedingSibling;
9160 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009161 case AXIS_SELF:
9162#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009163 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009164#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009165 first = NULL;
9166 last = NULL;
9167 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009168 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009169 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009170 }
9171 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009172 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009173
9174 nodelist = obj->nodesetval;
9175 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009176 xmlXPathFreeObject(obj);
9177 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9178 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009179 }
9180 addNode = xmlXPathNodeSetAddUnique;
9181 ret = NULL;
9182#ifdef DEBUG_STEP
9183 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009184 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009185 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009186 case NODE_TEST_NONE:
9187 xmlGenericError(xmlGenericErrorContext,
9188 " searching for none !!!\n");
9189 break;
9190 case NODE_TEST_TYPE:
9191 xmlGenericError(xmlGenericErrorContext,
9192 " searching for type %d\n", type);
9193 break;
9194 case NODE_TEST_PI:
9195 xmlGenericError(xmlGenericErrorContext,
9196 " searching for PI !!!\n");
9197 break;
9198 case NODE_TEST_ALL:
9199 xmlGenericError(xmlGenericErrorContext,
9200 " searching for *\n");
9201 break;
9202 case NODE_TEST_NS:
9203 xmlGenericError(xmlGenericErrorContext,
9204 " searching for namespace %s\n",
9205 prefix);
9206 break;
9207 case NODE_TEST_NAME:
9208 xmlGenericError(xmlGenericErrorContext,
9209 " searching for name %s\n", name);
9210 if (prefix != NULL)
9211 xmlGenericError(xmlGenericErrorContext,
9212 " with namespace %s\n", prefix);
9213 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009214 }
9215 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9216#endif
9217 /*
9218 * 2.3 Node Tests
9219 * - For the attribute axis, the principal node type is attribute.
9220 * - For the namespace axis, the principal node type is namespace.
9221 * - For other axes, the principal node type is element.
9222 *
9223 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009224 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009225 * select all element children of the context node
9226 */
9227 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009228 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009229 ctxt->context->node = nodelist->nodeTab[i];
9230
Daniel Veillardf06307e2001-07-03 10:35:50 +00009231 cur = NULL;
9232 list = xmlXPathNodeSetCreate(NULL);
9233 do {
9234 cur = next(ctxt, cur);
9235 if (cur == NULL)
9236 break;
9237 if ((first != NULL) && (*first == cur))
9238 break;
9239 if (((t % 256) == 0) &&
9240 (first != NULL) && (*first != NULL) &&
9241 (xmlXPathCmpNodes(*first, cur) >= 0))
9242 break;
9243 if ((last != NULL) && (*last == cur))
9244 break;
9245 if (((t % 256) == 0) &&
9246 (last != NULL) && (*last != NULL) &&
9247 (xmlXPathCmpNodes(cur, *last) >= 0))
9248 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009249 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009250#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009251 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9252#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009253 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009254 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009255 ctxt->context->node = tmp;
9256 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009257 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009258 if ((cur->type == type) ||
9259 ((type == NODE_TYPE_NODE) &&
9260 ((cur->type == XML_DOCUMENT_NODE) ||
9261 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9262 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009263 (cur->type == XML_NAMESPACE_DECL) ||
9264 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009265 (cur->type == XML_PI_NODE) ||
9266 (cur->type == XML_COMMENT_NODE) ||
9267 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009268 (cur->type == XML_TEXT_NODE))) ||
9269 ((type == NODE_TYPE_TEXT) &&
9270 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009271#ifdef DEBUG_STEP
9272 n++;
9273#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009274 addNode(list, cur);
9275 }
9276 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009277 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009278 if (cur->type == XML_PI_NODE) {
9279 if ((name != NULL) &&
9280 (!xmlStrEqual(name, cur->name)))
9281 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009282#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009283 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009284#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009285 addNode(list, cur);
9286 }
9287 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009288 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009289 if (axis == AXIS_ATTRIBUTE) {
9290 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009291#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009292 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009293#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009294 addNode(list, cur);
9295 }
9296 } else if (axis == AXIS_NAMESPACE) {
9297 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009298#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009299 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009300#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009301 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9302 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009303 }
9304 } else {
9305 if (cur->type == XML_ELEMENT_NODE) {
9306 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009307#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009308 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009309#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009310 addNode(list, cur);
9311 } else if ((cur->ns != NULL) &&
9312 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009313#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009314 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009315#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009316 addNode(list, cur);
9317 }
9318 }
9319 }
9320 break;
9321 case NODE_TEST_NS:{
9322 TODO;
9323 break;
9324 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009325 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009326 switch (cur->type) {
9327 case XML_ELEMENT_NODE:
9328 if (xmlStrEqual(name, cur->name)) {
9329 if (prefix == NULL) {
9330 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009331#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009332 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009333#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009334 addNode(list, cur);
9335 }
9336 } else {
9337 if ((cur->ns != NULL) &&
9338 (xmlStrEqual(URI,
9339 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009340#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009341 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009342#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009343 addNode(list, cur);
9344 }
9345 }
9346 }
9347 break;
9348 case XML_ATTRIBUTE_NODE:{
9349 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009350
Daniel Veillardf06307e2001-07-03 10:35:50 +00009351 if (xmlStrEqual(name, attr->name)) {
9352 if (prefix == NULL) {
9353 if ((attr->ns == NULL) ||
9354 (attr->ns->prefix == NULL)) {
9355#ifdef DEBUG_STEP
9356 n++;
9357#endif
9358 addNode(list,
9359 (xmlNodePtr) attr);
9360 }
9361 } else {
9362 if ((attr->ns != NULL) &&
9363 (xmlStrEqual(URI,
9364 attr->ns->
9365 href))) {
9366#ifdef DEBUG_STEP
9367 n++;
9368#endif
9369 addNode(list,
9370 (xmlNodePtr) attr);
9371 }
9372 }
9373 }
9374 break;
9375 }
9376 case XML_NAMESPACE_DECL:
9377 if (cur->type == XML_NAMESPACE_DECL) {
9378 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009379
Daniel Veillardf06307e2001-07-03 10:35:50 +00009380 if ((ns->prefix != NULL) && (name != NULL)
9381 && (xmlStrEqual(ns->prefix, name))) {
9382#ifdef DEBUG_STEP
9383 n++;
9384#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009385 xmlXPathNodeSetAddNs(list,
9386 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009387 }
9388 }
9389 break;
9390 default:
9391 break;
9392 }
9393 break;
9394 break;
9395 }
9396 } while (cur != NULL);
9397
9398 /*
9399 * If there is some predicate filtering do it now
9400 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009401 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009402 xmlXPathObjectPtr obj2;
9403
9404 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9405 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9406 CHECK_TYPE0(XPATH_NODESET);
9407 obj2 = valuePop(ctxt);
9408 list = obj2->nodesetval;
9409 obj2->nodesetval = NULL;
9410 xmlXPathFreeObject(obj2);
9411 }
9412 if (ret == NULL) {
9413 ret = list;
9414 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009415 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009416 xmlXPathFreeNodeSet(list);
9417 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009418 }
9419 ctxt->context->node = tmp;
9420#ifdef DEBUG_STEP
9421 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009422 "\nExamined %d nodes, found %d nodes at that step\n",
9423 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009424#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009425 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009426 if ((obj->boolval) && (obj->user != NULL)) {
9427 ctxt->value->boolval = 1;
9428 ctxt->value->user = obj->user;
9429 obj->user = NULL;
9430 obj->boolval = 0;
9431 }
9432 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009433 return(t);
9434}
9435
9436/**
9437 * xmlXPathNodeCollectAndTestNth:
9438 * @ctxt: the XPath Parser context
9439 * @op: the XPath precompiled step operation
9440 * @indx: the index to collect
9441 * @first: pointer to the first element in document order
9442 * @last: pointer to the last element in document order
9443 *
9444 * This is the function implementing a step: based on the current list
9445 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009446 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009447 *
9448 * Pushes the new NodeSet resulting from the search.
9449 * Returns the number of node traversed
9450 */
9451static int
9452xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9453 xmlXPathStepOpPtr op, int indx,
9454 xmlNodePtr * first, xmlNodePtr * last)
9455{
William M. Brack78637da2003-07-31 14:47:38 +00009456 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9457 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9458 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009459 const xmlChar *prefix = op->value4;
9460 const xmlChar *name = op->value5;
9461 const xmlChar *URI = NULL;
9462 int n = 0, t = 0;
9463
9464 int i;
9465 xmlNodeSetPtr list;
9466 xmlXPathTraversalFunction next = NULL;
9467 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9468 xmlNodePtr cur = NULL;
9469 xmlXPathObjectPtr obj;
9470 xmlNodeSetPtr nodelist;
9471 xmlNodePtr tmp;
9472
9473 CHECK_TYPE0(XPATH_NODESET);
9474 obj = valuePop(ctxt);
9475 addNode = xmlXPathNodeSetAdd;
9476 if (prefix != NULL) {
9477 URI = xmlXPathNsLookup(ctxt->context, prefix);
9478 if (URI == NULL)
9479 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9480 }
9481#ifdef DEBUG_STEP_NTH
9482 xmlGenericError(xmlGenericErrorContext, "new step : ");
9483 if (first != NULL) {
9484 if (*first != NULL)
9485 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9486 (*first)->name);
9487 else
9488 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9489 }
9490 if (last != NULL) {
9491 if (*last != NULL)
9492 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9493 (*last)->name);
9494 else
9495 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9496 }
9497#endif
9498 switch (axis) {
9499 case AXIS_ANCESTOR:
9500#ifdef DEBUG_STEP_NTH
9501 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9502#endif
9503 first = NULL;
9504 next = xmlXPathNextAncestor;
9505 break;
9506 case AXIS_ANCESTOR_OR_SELF:
9507#ifdef DEBUG_STEP_NTH
9508 xmlGenericError(xmlGenericErrorContext,
9509 "axis 'ancestors-or-self' ");
9510#endif
9511 first = NULL;
9512 next = xmlXPathNextAncestorOrSelf;
9513 break;
9514 case AXIS_ATTRIBUTE:
9515#ifdef DEBUG_STEP_NTH
9516 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9517#endif
9518 first = NULL;
9519 last = NULL;
9520 next = xmlXPathNextAttribute;
9521 break;
9522 case AXIS_CHILD:
9523#ifdef DEBUG_STEP_NTH
9524 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9525#endif
9526 last = NULL;
9527 next = xmlXPathNextChild;
9528 break;
9529 case AXIS_DESCENDANT:
9530#ifdef DEBUG_STEP_NTH
9531 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9532#endif
9533 last = NULL;
9534 next = xmlXPathNextDescendant;
9535 break;
9536 case AXIS_DESCENDANT_OR_SELF:
9537#ifdef DEBUG_STEP_NTH
9538 xmlGenericError(xmlGenericErrorContext,
9539 "axis 'descendant-or-self' ");
9540#endif
9541 last = NULL;
9542 next = xmlXPathNextDescendantOrSelf;
9543 break;
9544 case AXIS_FOLLOWING:
9545#ifdef DEBUG_STEP_NTH
9546 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9547#endif
9548 last = NULL;
9549 next = xmlXPathNextFollowing;
9550 break;
9551 case AXIS_FOLLOWING_SIBLING:
9552#ifdef DEBUG_STEP_NTH
9553 xmlGenericError(xmlGenericErrorContext,
9554 "axis 'following-siblings' ");
9555#endif
9556 last = NULL;
9557 next = xmlXPathNextFollowingSibling;
9558 break;
9559 case AXIS_NAMESPACE:
9560#ifdef DEBUG_STEP_NTH
9561 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9562#endif
9563 last = NULL;
9564 first = NULL;
9565 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9566 break;
9567 case AXIS_PARENT:
9568#ifdef DEBUG_STEP_NTH
9569 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9570#endif
9571 first = NULL;
9572 next = xmlXPathNextParent;
9573 break;
9574 case AXIS_PRECEDING:
9575#ifdef DEBUG_STEP_NTH
9576 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9577#endif
9578 first = NULL;
9579 next = xmlXPathNextPrecedingInternal;
9580 break;
9581 case AXIS_PRECEDING_SIBLING:
9582#ifdef DEBUG_STEP_NTH
9583 xmlGenericError(xmlGenericErrorContext,
9584 "axis 'preceding-sibling' ");
9585#endif
9586 first = NULL;
9587 next = xmlXPathNextPrecedingSibling;
9588 break;
9589 case AXIS_SELF:
9590#ifdef DEBUG_STEP_NTH
9591 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9592#endif
9593 first = NULL;
9594 last = NULL;
9595 next = xmlXPathNextSelf;
9596 break;
9597 }
9598 if (next == NULL)
9599 return(0);
9600
9601 nodelist = obj->nodesetval;
9602 if (nodelist == NULL) {
9603 xmlXPathFreeObject(obj);
9604 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9605 return(0);
9606 }
9607 addNode = xmlXPathNodeSetAddUnique;
9608#ifdef DEBUG_STEP_NTH
9609 xmlGenericError(xmlGenericErrorContext,
9610 " context contains %d nodes\n", nodelist->nodeNr);
9611 switch (test) {
9612 case NODE_TEST_NONE:
9613 xmlGenericError(xmlGenericErrorContext,
9614 " searching for none !!!\n");
9615 break;
9616 case NODE_TEST_TYPE:
9617 xmlGenericError(xmlGenericErrorContext,
9618 " searching for type %d\n", type);
9619 break;
9620 case NODE_TEST_PI:
9621 xmlGenericError(xmlGenericErrorContext,
9622 " searching for PI !!!\n");
9623 break;
9624 case NODE_TEST_ALL:
9625 xmlGenericError(xmlGenericErrorContext,
9626 " searching for *\n");
9627 break;
9628 case NODE_TEST_NS:
9629 xmlGenericError(xmlGenericErrorContext,
9630 " searching for namespace %s\n",
9631 prefix);
9632 break;
9633 case NODE_TEST_NAME:
9634 xmlGenericError(xmlGenericErrorContext,
9635 " searching for name %s\n", name);
9636 if (prefix != NULL)
9637 xmlGenericError(xmlGenericErrorContext,
9638 " with namespace %s\n", prefix);
9639 break;
9640 }
9641 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9642#endif
9643 /*
9644 * 2.3 Node Tests
9645 * - For the attribute axis, the principal node type is attribute.
9646 * - For the namespace axis, the principal node type is namespace.
9647 * - For other axes, the principal node type is element.
9648 *
9649 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009650 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009651 * select all element children of the context node
9652 */
9653 tmp = ctxt->context->node;
9654 list = xmlXPathNodeSetCreate(NULL);
9655 for (i = 0; i < nodelist->nodeNr; i++) {
9656 ctxt->context->node = nodelist->nodeTab[i];
9657
9658 cur = NULL;
9659 n = 0;
9660 do {
9661 cur = next(ctxt, cur);
9662 if (cur == NULL)
9663 break;
9664 if ((first != NULL) && (*first == cur))
9665 break;
9666 if (((t % 256) == 0) &&
9667 (first != NULL) && (*first != NULL) &&
9668 (xmlXPathCmpNodes(*first, cur) >= 0))
9669 break;
9670 if ((last != NULL) && (*last == cur))
9671 break;
9672 if (((t % 256) == 0) &&
9673 (last != NULL) && (*last != NULL) &&
9674 (xmlXPathCmpNodes(cur, *last) >= 0))
9675 break;
9676 t++;
9677 switch (test) {
9678 case NODE_TEST_NONE:
9679 ctxt->context->node = tmp;
9680 STRANGE return(0);
9681 case NODE_TEST_TYPE:
9682 if ((cur->type == type) ||
9683 ((type == NODE_TYPE_NODE) &&
9684 ((cur->type == XML_DOCUMENT_NODE) ||
9685 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9686 (cur->type == XML_ELEMENT_NODE) ||
9687 (cur->type == XML_PI_NODE) ||
9688 (cur->type == XML_COMMENT_NODE) ||
9689 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009690 (cur->type == XML_TEXT_NODE))) ||
9691 ((type == NODE_TYPE_TEXT) &&
9692 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009693 n++;
9694 if (n == indx)
9695 addNode(list, cur);
9696 }
9697 break;
9698 case NODE_TEST_PI:
9699 if (cur->type == XML_PI_NODE) {
9700 if ((name != NULL) &&
9701 (!xmlStrEqual(name, cur->name)))
9702 break;
9703 n++;
9704 if (n == indx)
9705 addNode(list, cur);
9706 }
9707 break;
9708 case NODE_TEST_ALL:
9709 if (axis == AXIS_ATTRIBUTE) {
9710 if (cur->type == XML_ATTRIBUTE_NODE) {
9711 n++;
9712 if (n == indx)
9713 addNode(list, cur);
9714 }
9715 } else if (axis == AXIS_NAMESPACE) {
9716 if (cur->type == XML_NAMESPACE_DECL) {
9717 n++;
9718 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009719 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9720 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009721 }
9722 } else {
9723 if (cur->type == XML_ELEMENT_NODE) {
9724 if (prefix == NULL) {
9725 n++;
9726 if (n == indx)
9727 addNode(list, cur);
9728 } else if ((cur->ns != NULL) &&
9729 (xmlStrEqual(URI, cur->ns->href))) {
9730 n++;
9731 if (n == indx)
9732 addNode(list, cur);
9733 }
9734 }
9735 }
9736 break;
9737 case NODE_TEST_NS:{
9738 TODO;
9739 break;
9740 }
9741 case NODE_TEST_NAME:
9742 switch (cur->type) {
9743 case XML_ELEMENT_NODE:
9744 if (xmlStrEqual(name, cur->name)) {
9745 if (prefix == NULL) {
9746 if (cur->ns == NULL) {
9747 n++;
9748 if (n == indx)
9749 addNode(list, cur);
9750 }
9751 } else {
9752 if ((cur->ns != NULL) &&
9753 (xmlStrEqual(URI,
9754 cur->ns->href))) {
9755 n++;
9756 if (n == indx)
9757 addNode(list, cur);
9758 }
9759 }
9760 }
9761 break;
9762 case XML_ATTRIBUTE_NODE:{
9763 xmlAttrPtr attr = (xmlAttrPtr) cur;
9764
9765 if (xmlStrEqual(name, attr->name)) {
9766 if (prefix == NULL) {
9767 if ((attr->ns == NULL) ||
9768 (attr->ns->prefix == NULL)) {
9769 n++;
9770 if (n == indx)
9771 addNode(list, cur);
9772 }
9773 } else {
9774 if ((attr->ns != NULL) &&
9775 (xmlStrEqual(URI,
9776 attr->ns->
9777 href))) {
9778 n++;
9779 if (n == indx)
9780 addNode(list, cur);
9781 }
9782 }
9783 }
9784 break;
9785 }
9786 case XML_NAMESPACE_DECL:
9787 if (cur->type == XML_NAMESPACE_DECL) {
9788 xmlNsPtr ns = (xmlNsPtr) cur;
9789
9790 if ((ns->prefix != NULL) && (name != NULL)
9791 && (xmlStrEqual(ns->prefix, name))) {
9792 n++;
9793 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009794 xmlXPathNodeSetAddNs(list,
9795 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009796 }
9797 }
9798 break;
9799 default:
9800 break;
9801 }
9802 break;
9803 break;
9804 }
9805 } while (n < indx);
9806 }
9807 ctxt->context->node = tmp;
9808#ifdef DEBUG_STEP_NTH
9809 xmlGenericError(xmlGenericErrorContext,
9810 "\nExamined %d nodes, found %d nodes at that step\n",
9811 t, list->nodeNr);
9812#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009813 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009814 if ((obj->boolval) && (obj->user != NULL)) {
9815 ctxt->value->boolval = 1;
9816 ctxt->value->user = obj->user;
9817 obj->user = NULL;
9818 obj->boolval = 0;
9819 }
9820 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009821 return(t);
9822}
9823
9824/**
9825 * xmlXPathCompOpEvalFirst:
9826 * @ctxt: the XPath parser context with the compiled expression
9827 * @op: an XPath compiled operation
9828 * @first: the first elem found so far
9829 *
9830 * Evaluate the Precompiled XPath operation searching only the first
9831 * element in document order
9832 *
9833 * Returns the number of examined objects.
9834 */
9835static int
9836xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9837 xmlXPathStepOpPtr op, xmlNodePtr * first)
9838{
9839 int total = 0, cur;
9840 xmlXPathCompExprPtr comp;
9841 xmlXPathObjectPtr arg1, arg2;
9842
Daniel Veillard556c6682001-10-06 09:59:51 +00009843 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009844 comp = ctxt->comp;
9845 switch (op->op) {
9846 case XPATH_OP_END:
9847 return (0);
9848 case XPATH_OP_UNION:
9849 total =
9850 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9851 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009852 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009853 if ((ctxt->value != NULL)
9854 && (ctxt->value->type == XPATH_NODESET)
9855 && (ctxt->value->nodesetval != NULL)
9856 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9857 /*
9858 * limit tree traversing to first node in the result
9859 */
9860 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9861 *first = ctxt->value->nodesetval->nodeTab[0];
9862 }
9863 cur =
9864 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9865 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009866 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009867 CHECK_TYPE0(XPATH_NODESET);
9868 arg2 = valuePop(ctxt);
9869
9870 CHECK_TYPE0(XPATH_NODESET);
9871 arg1 = valuePop(ctxt);
9872
9873 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9874 arg2->nodesetval);
9875 valuePush(ctxt, arg1);
9876 xmlXPathFreeObject(arg2);
9877 /* optimizer */
9878 if (total > cur)
9879 xmlXPathCompSwap(op);
9880 return (total + cur);
9881 case XPATH_OP_ROOT:
9882 xmlXPathRoot(ctxt);
9883 return (0);
9884 case XPATH_OP_NODE:
9885 if (op->ch1 != -1)
9886 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009887 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009888 if (op->ch2 != -1)
9889 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009890 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009891 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9892 return (total);
9893 case XPATH_OP_RESET:
9894 if (op->ch1 != -1)
9895 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009896 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009897 if (op->ch2 != -1)
9898 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009899 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009900 ctxt->context->node = NULL;
9901 return (total);
9902 case XPATH_OP_COLLECT:{
9903 if (op->ch1 == -1)
9904 return (total);
9905
9906 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009907 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009908
9909 /*
9910 * Optimization for [n] selection where n is a number
9911 */
9912 if ((op->ch2 != -1) &&
9913 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9914 (comp->steps[op->ch2].ch1 == -1) &&
9915 (comp->steps[op->ch2].ch2 != -1) &&
9916 (comp->steps[comp->steps[op->ch2].ch2].op ==
9917 XPATH_OP_VALUE)) {
9918 xmlXPathObjectPtr val;
9919
9920 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9921 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9922 int indx = (int) val->floatval;
9923
9924 if (val->floatval == (float) indx) {
9925 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9926 first, NULL);
9927 return (total);
9928 }
9929 }
9930 }
9931 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9932 return (total);
9933 }
9934 case XPATH_OP_VALUE:
9935 valuePush(ctxt,
9936 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9937 return (0);
9938 case XPATH_OP_SORT:
9939 if (op->ch1 != -1)
9940 total +=
9941 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9942 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009943 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009944 if ((ctxt->value != NULL)
9945 && (ctxt->value->type == XPATH_NODESET)
9946 && (ctxt->value->nodesetval != NULL))
9947 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9948 return (total);
9949 default:
9950 return (xmlXPathCompOpEval(ctxt, op));
9951 }
9952}
9953
9954/**
9955 * xmlXPathCompOpEvalLast:
9956 * @ctxt: the XPath parser context with the compiled expression
9957 * @op: an XPath compiled operation
9958 * @last: the last elem found so far
9959 *
9960 * Evaluate the Precompiled XPath operation searching only the last
9961 * element in document order
9962 *
William M. Brack08171912003-12-29 02:52:11 +00009963 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +00009964 */
9965static int
9966xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9967 xmlNodePtr * last)
9968{
9969 int total = 0, cur;
9970 xmlXPathCompExprPtr comp;
9971 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +00009972 xmlNodePtr bak;
9973 xmlDocPtr bakd;
9974 int pp;
9975 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009976
Daniel Veillard556c6682001-10-06 09:59:51 +00009977 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009978 comp = ctxt->comp;
9979 switch (op->op) {
9980 case XPATH_OP_END:
9981 return (0);
9982 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +00009983 bakd = ctxt->context->doc;
9984 bak = ctxt->context->node;
9985 pp = ctxt->context->proximityPosition;
9986 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009987 total =
9988 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009989 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009990 if ((ctxt->value != NULL)
9991 && (ctxt->value->type == XPATH_NODESET)
9992 && (ctxt->value->nodesetval != NULL)
9993 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9994 /*
9995 * limit tree traversing to first node in the result
9996 */
9997 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9998 *last =
9999 ctxt->value->nodesetval->nodeTab[ctxt->value->
10000 nodesetval->nodeNr -
10001 1];
10002 }
William M. Brackce4fc562004-01-22 02:47:18 +000010003 ctxt->context->doc = bakd;
10004 ctxt->context->node = bak;
10005 ctxt->context->proximityPosition = pp;
10006 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010007 cur =
10008 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010009 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010010 if ((ctxt->value != NULL)
10011 && (ctxt->value->type == XPATH_NODESET)
10012 && (ctxt->value->nodesetval != NULL)
10013 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10014 }
10015 CHECK_TYPE0(XPATH_NODESET);
10016 arg2 = valuePop(ctxt);
10017
10018 CHECK_TYPE0(XPATH_NODESET);
10019 arg1 = valuePop(ctxt);
10020
10021 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10022 arg2->nodesetval);
10023 valuePush(ctxt, arg1);
10024 xmlXPathFreeObject(arg2);
10025 /* optimizer */
10026 if (total > cur)
10027 xmlXPathCompSwap(op);
10028 return (total + cur);
10029 case XPATH_OP_ROOT:
10030 xmlXPathRoot(ctxt);
10031 return (0);
10032 case XPATH_OP_NODE:
10033 if (op->ch1 != -1)
10034 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010035 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010036 if (op->ch2 != -1)
10037 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010038 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010039 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10040 return (total);
10041 case XPATH_OP_RESET:
10042 if (op->ch1 != -1)
10043 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010044 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010045 if (op->ch2 != -1)
10046 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010047 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010048 ctxt->context->node = NULL;
10049 return (total);
10050 case XPATH_OP_COLLECT:{
10051 if (op->ch1 == -1)
10052 return (0);
10053
10054 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010055 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010056
10057 /*
10058 * Optimization for [n] selection where n is a number
10059 */
10060 if ((op->ch2 != -1) &&
10061 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10062 (comp->steps[op->ch2].ch1 == -1) &&
10063 (comp->steps[op->ch2].ch2 != -1) &&
10064 (comp->steps[comp->steps[op->ch2].ch2].op ==
10065 XPATH_OP_VALUE)) {
10066 xmlXPathObjectPtr val;
10067
10068 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10069 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10070 int indx = (int) val->floatval;
10071
10072 if (val->floatval == (float) indx) {
10073 total +=
10074 xmlXPathNodeCollectAndTestNth(ctxt, op,
10075 indx, NULL,
10076 last);
10077 return (total);
10078 }
10079 }
10080 }
10081 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10082 return (total);
10083 }
10084 case XPATH_OP_VALUE:
10085 valuePush(ctxt,
10086 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10087 return (0);
10088 case XPATH_OP_SORT:
10089 if (op->ch1 != -1)
10090 total +=
10091 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10092 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010093 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010094 if ((ctxt->value != NULL)
10095 && (ctxt->value->type == XPATH_NODESET)
10096 && (ctxt->value->nodesetval != NULL))
10097 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10098 return (total);
10099 default:
10100 return (xmlXPathCompOpEval(ctxt, op));
10101 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010102}
10103
Owen Taylor3473f882001-02-23 17:55:21 +000010104/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010105 * xmlXPathCompOpEval:
10106 * @ctxt: the XPath parser context with the compiled expression
10107 * @op: an XPath compiled operation
10108 *
10109 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010110 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010111 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010112static int
10113xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10114{
10115 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010116 int equal, ret;
10117 xmlXPathCompExprPtr comp;
10118 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010119 xmlNodePtr bak;
10120 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010121 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010122 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010123
Daniel Veillard556c6682001-10-06 09:59:51 +000010124 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010125 comp = ctxt->comp;
10126 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010127 case XPATH_OP_END:
10128 return (0);
10129 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010130 bakd = ctxt->context->doc;
10131 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010132 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010133 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010134 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010135 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010136 xmlXPathBooleanFunction(ctxt, 1);
10137 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10138 return (total);
10139 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010140 ctxt->context->doc = bakd;
10141 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010142 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010143 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010144 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010145 if (ctxt->error) {
10146 xmlXPathFreeObject(arg2);
10147 return(0);
10148 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010149 xmlXPathBooleanFunction(ctxt, 1);
10150 arg1 = valuePop(ctxt);
10151 arg1->boolval &= arg2->boolval;
10152 valuePush(ctxt, arg1);
10153 xmlXPathFreeObject(arg2);
10154 return (total);
10155 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010156 bakd = ctxt->context->doc;
10157 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010158 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010159 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010160 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010161 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010162 xmlXPathBooleanFunction(ctxt, 1);
10163 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10164 return (total);
10165 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010166 ctxt->context->doc = bakd;
10167 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010168 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010169 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010170 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010171 if (ctxt->error) {
10172 xmlXPathFreeObject(arg2);
10173 return(0);
10174 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010175 xmlXPathBooleanFunction(ctxt, 1);
10176 arg1 = valuePop(ctxt);
10177 arg1->boolval |= arg2->boolval;
10178 valuePush(ctxt, arg1);
10179 xmlXPathFreeObject(arg2);
10180 return (total);
10181 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010182 bakd = ctxt->context->doc;
10183 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010184 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010185 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010186 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010187 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010188 ctxt->context->doc = bakd;
10189 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010190 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010191 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010192 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010193 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010194 if (op->value)
10195 equal = xmlXPathEqualValues(ctxt);
10196 else
10197 equal = xmlXPathNotEqualValues(ctxt);
10198 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010199 return (total);
10200 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010201 bakd = ctxt->context->doc;
10202 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010203 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010204 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010205 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010206 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010207 ctxt->context->doc = bakd;
10208 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010209 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010210 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010211 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010212 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010213 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10214 valuePush(ctxt, xmlXPathNewBoolean(ret));
10215 return (total);
10216 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010217 bakd = ctxt->context->doc;
10218 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010219 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010220 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010221 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010222 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010223 if (op->ch2 != -1) {
10224 ctxt->context->doc = bakd;
10225 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010226 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010227 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010228 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010229 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010230 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010231 if (op->value == 0)
10232 xmlXPathSubValues(ctxt);
10233 else if (op->value == 1)
10234 xmlXPathAddValues(ctxt);
10235 else if (op->value == 2)
10236 xmlXPathValueFlipSign(ctxt);
10237 else if (op->value == 3) {
10238 CAST_TO_NUMBER;
10239 CHECK_TYPE0(XPATH_NUMBER);
10240 }
10241 return (total);
10242 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010243 bakd = ctxt->context->doc;
10244 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010245 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010246 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010247 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010248 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010249 ctxt->context->doc = bakd;
10250 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010251 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010252 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010253 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010254 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010255 if (op->value == 0)
10256 xmlXPathMultValues(ctxt);
10257 else if (op->value == 1)
10258 xmlXPathDivValues(ctxt);
10259 else if (op->value == 2)
10260 xmlXPathModValues(ctxt);
10261 return (total);
10262 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010263 bakd = ctxt->context->doc;
10264 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010265 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010266 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010267 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010268 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010269 ctxt->context->doc = bakd;
10270 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010271 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010272 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010273 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010274 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010275 CHECK_TYPE0(XPATH_NODESET);
10276 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010277
Daniel Veillardf06307e2001-07-03 10:35:50 +000010278 CHECK_TYPE0(XPATH_NODESET);
10279 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010280
Daniel Veillardf06307e2001-07-03 10:35:50 +000010281 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10282 arg2->nodesetval);
10283 valuePush(ctxt, arg1);
10284 xmlXPathFreeObject(arg2);
10285 return (total);
10286 case XPATH_OP_ROOT:
10287 xmlXPathRoot(ctxt);
10288 return (total);
10289 case XPATH_OP_NODE:
10290 if (op->ch1 != -1)
10291 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010292 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010293 if (op->ch2 != -1)
10294 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010295 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010296 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10297 return (total);
10298 case XPATH_OP_RESET:
10299 if (op->ch1 != -1)
10300 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010301 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010302 if (op->ch2 != -1)
10303 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010304 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010305 ctxt->context->node = NULL;
10306 return (total);
10307 case XPATH_OP_COLLECT:{
10308 if (op->ch1 == -1)
10309 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010310
Daniel Veillardf06307e2001-07-03 10:35:50 +000010311 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010312 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010313
Daniel Veillardf06307e2001-07-03 10:35:50 +000010314 /*
10315 * Optimization for [n] selection where n is a number
10316 */
10317 if ((op->ch2 != -1) &&
10318 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10319 (comp->steps[op->ch2].ch1 == -1) &&
10320 (comp->steps[op->ch2].ch2 != -1) &&
10321 (comp->steps[comp->steps[op->ch2].ch2].op ==
10322 XPATH_OP_VALUE)) {
10323 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010324
Daniel Veillardf06307e2001-07-03 10:35:50 +000010325 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10326 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10327 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010328
Daniel Veillardf06307e2001-07-03 10:35:50 +000010329 if (val->floatval == (float) indx) {
10330 total +=
10331 xmlXPathNodeCollectAndTestNth(ctxt, op,
10332 indx, NULL,
10333 NULL);
10334 return (total);
10335 }
10336 }
10337 }
10338 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10339 return (total);
10340 }
10341 case XPATH_OP_VALUE:
10342 valuePush(ctxt,
10343 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10344 return (total);
10345 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010346 xmlXPathObjectPtr val;
10347
Daniel Veillardf06307e2001-07-03 10:35:50 +000010348 if (op->ch1 != -1)
10349 total +=
10350 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010351 if (op->value5 == NULL) {
10352 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10353 if (val == NULL) {
10354 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10355 return(0);
10356 }
10357 valuePush(ctxt, val);
10358 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010359 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010360
Daniel Veillardf06307e2001-07-03 10:35:50 +000010361 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10362 if (URI == NULL) {
10363 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010364 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010365 op->value4, op->value5);
10366 return (total);
10367 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010368 val = xmlXPathVariableLookupNS(ctxt->context,
10369 op->value4, URI);
10370 if (val == NULL) {
10371 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10372 return(0);
10373 }
10374 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010375 }
10376 return (total);
10377 }
10378 case XPATH_OP_FUNCTION:{
10379 xmlXPathFunction func;
10380 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010381 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010382
10383 if (op->ch1 != -1)
10384 total +=
10385 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010386 if (ctxt->valueNr < op->value) {
10387 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010388 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010389 ctxt->error = XPATH_INVALID_OPERAND;
10390 return (total);
10391 }
10392 for (i = 0; i < op->value; i++)
10393 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10394 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010395 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010396 ctxt->error = XPATH_INVALID_OPERAND;
10397 return (total);
10398 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010399 if (op->cache != NULL)
10400 func = (xmlXPathFunction) op->cache;
10401 else {
10402 const xmlChar *URI = NULL;
10403
10404 if (op->value5 == NULL)
10405 func =
10406 xmlXPathFunctionLookup(ctxt->context,
10407 op->value4);
10408 else {
10409 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10410 if (URI == NULL) {
10411 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010412 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010413 op->value4, op->value5);
10414 return (total);
10415 }
10416 func = xmlXPathFunctionLookupNS(ctxt->context,
10417 op->value4, URI);
10418 }
10419 if (func == NULL) {
10420 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010421 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010422 op->value4);
10423 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010424 }
10425 op->cache = (void *) func;
10426 op->cacheURI = (void *) URI;
10427 }
10428 oldFunc = ctxt->context->function;
10429 oldFuncURI = ctxt->context->functionURI;
10430 ctxt->context->function = op->value4;
10431 ctxt->context->functionURI = op->cacheURI;
10432 func(ctxt, op->value);
10433 ctxt->context->function = oldFunc;
10434 ctxt->context->functionURI = oldFuncURI;
10435 return (total);
10436 }
10437 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010438 bakd = ctxt->context->doc;
10439 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000010440 pp = ctxt->context->proximityPosition;
10441 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010442 if (op->ch1 != -1)
10443 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000010444 ctxt->context->contextSize = cs;
10445 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000010446 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000010447 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000010448 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010449 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010450 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010451 ctxt->context->doc = bakd;
10452 ctxt->context->node = bak;
10453 CHECK_ERROR0;
10454 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010455 return (total);
10456 case XPATH_OP_PREDICATE:
10457 case XPATH_OP_FILTER:{
10458 xmlXPathObjectPtr res;
10459 xmlXPathObjectPtr obj, tmp;
10460 xmlNodeSetPtr newset = NULL;
10461 xmlNodeSetPtr oldset;
10462 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000010463 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010464 int i;
10465
10466 /*
10467 * Optimization for ()[1] selection i.e. the first elem
10468 */
10469 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10470 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10471 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10472 xmlXPathObjectPtr val;
10473
10474 val = comp->steps[op->ch2].value4;
10475 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10476 (val->floatval == 1.0)) {
10477 xmlNodePtr first = NULL;
10478
10479 total +=
10480 xmlXPathCompOpEvalFirst(ctxt,
10481 &comp->steps[op->ch1],
10482 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010483 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010484 /*
10485 * The nodeset should be in document order,
10486 * Keep only the first value
10487 */
10488 if ((ctxt->value != NULL) &&
10489 (ctxt->value->type == XPATH_NODESET) &&
10490 (ctxt->value->nodesetval != NULL) &&
10491 (ctxt->value->nodesetval->nodeNr > 1))
10492 ctxt->value->nodesetval->nodeNr = 1;
10493 return (total);
10494 }
10495 }
10496 /*
10497 * Optimization for ()[last()] selection i.e. the last elem
10498 */
10499 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10500 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10501 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10502 int f = comp->steps[op->ch2].ch1;
10503
10504 if ((f != -1) &&
10505 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10506 (comp->steps[f].value5 == NULL) &&
10507 (comp->steps[f].value == 0) &&
10508 (comp->steps[f].value4 != NULL) &&
10509 (xmlStrEqual
10510 (comp->steps[f].value4, BAD_CAST "last"))) {
10511 xmlNodePtr last = NULL;
10512
10513 total +=
10514 xmlXPathCompOpEvalLast(ctxt,
10515 &comp->steps[op->ch1],
10516 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010517 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010518 /*
10519 * The nodeset should be in document order,
10520 * Keep only the last value
10521 */
10522 if ((ctxt->value != NULL) &&
10523 (ctxt->value->type == XPATH_NODESET) &&
10524 (ctxt->value->nodesetval != NULL) &&
10525 (ctxt->value->nodesetval->nodeTab != NULL) &&
10526 (ctxt->value->nodesetval->nodeNr > 1)) {
10527 ctxt->value->nodesetval->nodeTab[0] =
10528 ctxt->value->nodesetval->nodeTab[ctxt->
10529 value->
10530 nodesetval->
10531 nodeNr -
10532 1];
10533 ctxt->value->nodesetval->nodeNr = 1;
10534 }
10535 return (total);
10536 }
10537 }
10538
10539 if (op->ch1 != -1)
10540 total +=
10541 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010542 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010543 if (op->ch2 == -1)
10544 return (total);
10545 if (ctxt->value == NULL)
10546 return (total);
10547
10548 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010549
10550#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010551 /*
10552 * Hum are we filtering the result of an XPointer expression
10553 */
10554 if (ctxt->value->type == XPATH_LOCATIONSET) {
10555 xmlLocationSetPtr newlocset = NULL;
10556 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010557
Daniel Veillardf06307e2001-07-03 10:35:50 +000010558 /*
10559 * Extract the old locset, and then evaluate the result of the
10560 * expression for all the element in the locset. use it to grow
10561 * up a new locset.
10562 */
10563 CHECK_TYPE0(XPATH_LOCATIONSET);
10564 obj = valuePop(ctxt);
10565 oldlocset = obj->user;
10566 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010567
Daniel Veillardf06307e2001-07-03 10:35:50 +000010568 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10569 ctxt->context->contextSize = 0;
10570 ctxt->context->proximityPosition = 0;
10571 if (op->ch2 != -1)
10572 total +=
10573 xmlXPathCompOpEval(ctxt,
10574 &comp->steps[op->ch2]);
10575 res = valuePop(ctxt);
10576 if (res != NULL)
10577 xmlXPathFreeObject(res);
10578 valuePush(ctxt, obj);
10579 CHECK_ERROR0;
10580 return (total);
10581 }
10582 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010583
Daniel Veillardf06307e2001-07-03 10:35:50 +000010584 for (i = 0; i < oldlocset->locNr; i++) {
10585 /*
10586 * Run the evaluation with a node list made of a
10587 * single item in the nodelocset.
10588 */
10589 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010590 ctxt->context->contextSize = oldlocset->locNr;
10591 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010592 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10593 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010594
Daniel Veillardf06307e2001-07-03 10:35:50 +000010595 if (op->ch2 != -1)
10596 total +=
10597 xmlXPathCompOpEval(ctxt,
10598 &comp->steps[op->ch2]);
10599 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010600
Daniel Veillardf06307e2001-07-03 10:35:50 +000010601 /*
10602 * The result of the evaluation need to be tested to
10603 * decided whether the filter succeeded or not
10604 */
10605 res = valuePop(ctxt);
10606 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10607 xmlXPtrLocationSetAdd(newlocset,
10608 xmlXPathObjectCopy
10609 (oldlocset->locTab[i]));
10610 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010611
Daniel Veillardf06307e2001-07-03 10:35:50 +000010612 /*
10613 * Cleanup
10614 */
10615 if (res != NULL)
10616 xmlXPathFreeObject(res);
10617 if (ctxt->value == tmp) {
10618 res = valuePop(ctxt);
10619 xmlXPathFreeObject(res);
10620 }
10621
10622 ctxt->context->node = NULL;
10623 }
10624
10625 /*
10626 * The result is used as the new evaluation locset.
10627 */
10628 xmlXPathFreeObject(obj);
10629 ctxt->context->node = NULL;
10630 ctxt->context->contextSize = -1;
10631 ctxt->context->proximityPosition = -1;
10632 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10633 ctxt->context->node = oldnode;
10634 return (total);
10635 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010636#endif /* LIBXML_XPTR_ENABLED */
10637
Daniel Veillardf06307e2001-07-03 10:35:50 +000010638 /*
10639 * Extract the old set, and then evaluate the result of the
10640 * expression for all the element in the set. use it to grow
10641 * up a new set.
10642 */
10643 CHECK_TYPE0(XPATH_NODESET);
10644 obj = valuePop(ctxt);
10645 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010646
Daniel Veillardf06307e2001-07-03 10:35:50 +000010647 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000010648 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010649 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010650
Daniel Veillardf06307e2001-07-03 10:35:50 +000010651 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10652 ctxt->context->contextSize = 0;
10653 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000010654/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000010655 if (op->ch2 != -1)
10656 total +=
10657 xmlXPathCompOpEval(ctxt,
10658 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010659 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010660 res = valuePop(ctxt);
10661 if (res != NULL)
10662 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000010663*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000010664 valuePush(ctxt, obj);
10665 ctxt->context->node = oldnode;
10666 CHECK_ERROR0;
10667 } else {
10668 /*
10669 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000010670 * Also set the xpath document in case things like
10671 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000010672 */
10673 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010674
Daniel Veillardf06307e2001-07-03 10:35:50 +000010675 for (i = 0; i < oldset->nodeNr; i++) {
10676 /*
10677 * Run the evaluation with a node list made of
10678 * a single item in the nodeset.
10679 */
10680 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000010681 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
10682 (oldset->nodeTab[i]->doc != NULL))
10683 ctxt->context->doc = oldset->nodeTab[i]->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010684 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10685 valuePush(ctxt, tmp);
10686 ctxt->context->contextSize = oldset->nodeNr;
10687 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010688
Daniel Veillardf06307e2001-07-03 10:35:50 +000010689 if (op->ch2 != -1)
10690 total +=
10691 xmlXPathCompOpEval(ctxt,
10692 &comp->steps[op->ch2]);
10693 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010694
Daniel Veillardf06307e2001-07-03 10:35:50 +000010695 /*
William M. Brack08171912003-12-29 02:52:11 +000010696 * The result of the evaluation needs to be tested to
10697 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010698 */
10699 res = valuePop(ctxt);
10700 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10701 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10702 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010703
Daniel Veillardf06307e2001-07-03 10:35:50 +000010704 /*
10705 * Cleanup
10706 */
10707 if (res != NULL)
10708 xmlXPathFreeObject(res);
10709 if (ctxt->value == tmp) {
10710 res = valuePop(ctxt);
10711 xmlXPathFreeObject(res);
10712 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010713
Daniel Veillardf06307e2001-07-03 10:35:50 +000010714 ctxt->context->node = NULL;
10715 }
10716
10717 /*
10718 * The result is used as the new evaluation set.
10719 */
10720 xmlXPathFreeObject(obj);
10721 ctxt->context->node = NULL;
10722 ctxt->context->contextSize = -1;
10723 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000010724 /* may want to move this past the '}' later */
10725 ctxt->context->doc = oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010726 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10727 }
10728 ctxt->context->node = oldnode;
10729 return (total);
10730 }
10731 case XPATH_OP_SORT:
10732 if (op->ch1 != -1)
10733 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010734 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010735 if ((ctxt->value != NULL) &&
10736 (ctxt->value->type == XPATH_NODESET) &&
10737 (ctxt->value->nodesetval != NULL))
10738 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10739 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010740#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010741 case XPATH_OP_RANGETO:{
10742 xmlXPathObjectPtr range;
10743 xmlXPathObjectPtr res, obj;
10744 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010745 xmlLocationSetPtr newlocset = NULL;
10746 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010747 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000010748 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010749
Daniel Veillardf06307e2001-07-03 10:35:50 +000010750 if (op->ch1 != -1)
10751 total +=
10752 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10753 if (op->ch2 == -1)
10754 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010755
William M. Brack08171912003-12-29 02:52:11 +000010756 if (ctxt->value->type == XPATH_LOCATIONSET) {
10757 /*
10758 * Extract the old locset, and then evaluate the result of the
10759 * expression for all the element in the locset. use it to grow
10760 * up a new locset.
10761 */
10762 CHECK_TYPE0(XPATH_LOCATIONSET);
10763 obj = valuePop(ctxt);
10764 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010765
William M. Brack08171912003-12-29 02:52:11 +000010766 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000010767 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000010768 ctxt->context->contextSize = 0;
10769 ctxt->context->proximityPosition = 0;
10770 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10771 res = valuePop(ctxt);
10772 if (res != NULL)
10773 xmlXPathFreeObject(res);
10774 valuePush(ctxt, obj);
10775 CHECK_ERROR0;
10776 return (total);
10777 }
10778 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010779
William M. Brack08171912003-12-29 02:52:11 +000010780 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010781 /*
William M. Brack08171912003-12-29 02:52:11 +000010782 * Run the evaluation with a node list made of a
10783 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010784 */
William M. Brackf7eb7942003-12-31 07:59:17 +000010785 ctxt->context->node = oldlocset->locTab[i]->user;
10786 ctxt->context->contextSize = oldlocset->locNr;
10787 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010788 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10789 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010790
Daniel Veillardf06307e2001-07-03 10:35:50 +000010791 if (op->ch2 != -1)
10792 total +=
10793 xmlXPathCompOpEval(ctxt,
10794 &comp->steps[op->ch2]);
10795 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010796
Daniel Veillardf06307e2001-07-03 10:35:50 +000010797 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000010798 if (res->type == XPATH_LOCATIONSET) {
10799 xmlLocationSetPtr rloc =
10800 (xmlLocationSetPtr)res->user;
10801 for (j=0; j<rloc->locNr; j++) {
10802 range = xmlXPtrNewRange(
10803 oldlocset->locTab[i]->user,
10804 oldlocset->locTab[i]->index,
10805 rloc->locTab[j]->user2,
10806 rloc->locTab[j]->index2);
10807 if (range != NULL) {
10808 xmlXPtrLocationSetAdd(newlocset, range);
10809 }
10810 }
10811 } else {
10812 range = xmlXPtrNewRangeNodeObject(
10813 (xmlNodePtr)oldlocset->locTab[i]->user, res);
10814 if (range != NULL) {
10815 xmlXPtrLocationSetAdd(newlocset,range);
10816 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010817 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010818
Daniel Veillardf06307e2001-07-03 10:35:50 +000010819 /*
10820 * Cleanup
10821 */
10822 if (res != NULL)
10823 xmlXPathFreeObject(res);
10824 if (ctxt->value == tmp) {
10825 res = valuePop(ctxt);
10826 xmlXPathFreeObject(res);
10827 }
10828
10829 ctxt->context->node = NULL;
10830 }
William M. Brack72ee48d2003-12-30 08:30:19 +000010831 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000010832 CHECK_TYPE0(XPATH_NODESET);
10833 obj = valuePop(ctxt);
10834 oldset = obj->nodesetval;
10835 ctxt->context->node = NULL;
10836
10837 newlocset = xmlXPtrLocationSetCreate(NULL);
10838
10839 if (oldset != NULL) {
10840 for (i = 0; i < oldset->nodeNr; i++) {
10841 /*
10842 * Run the evaluation with a node list made of a single item
10843 * in the nodeset.
10844 */
10845 ctxt->context->node = oldset->nodeTab[i];
10846 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10847 valuePush(ctxt, tmp);
10848
10849 if (op->ch2 != -1)
10850 total +=
10851 xmlXPathCompOpEval(ctxt,
10852 &comp->steps[op->ch2]);
10853 CHECK_ERROR0;
10854
William M. Brack08171912003-12-29 02:52:11 +000010855 res = valuePop(ctxt);
10856 range =
10857 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10858 res);
10859 if (range != NULL) {
10860 xmlXPtrLocationSetAdd(newlocset, range);
10861 }
10862
10863 /*
10864 * Cleanup
10865 */
10866 if (res != NULL)
10867 xmlXPathFreeObject(res);
10868 if (ctxt->value == tmp) {
10869 res = valuePop(ctxt);
10870 xmlXPathFreeObject(res);
10871 }
10872
10873 ctxt->context->node = NULL;
10874 }
10875 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010876 }
10877
10878 /*
10879 * The result is used as the new evaluation set.
10880 */
10881 xmlXPathFreeObject(obj);
10882 ctxt->context->node = NULL;
10883 ctxt->context->contextSize = -1;
10884 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010885 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010886 return (total);
10887 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010888#endif /* LIBXML_XPTR_ENABLED */
10889 }
10890 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010891 "XPath: unknown precompiled operation %d\n", op->op);
10892 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010893}
10894
10895/**
10896 * xmlXPathRunEval:
10897 * @ctxt: the XPath parser context with the compiled expression
10898 *
10899 * Evaluate the Precompiled XPath expression in the given context.
10900 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010901static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010902xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10903 xmlXPathCompExprPtr comp;
10904
10905 if ((ctxt == NULL) || (ctxt->comp == NULL))
10906 return;
10907
10908 if (ctxt->valueTab == NULL) {
10909 /* Allocate the value stack */
10910 ctxt->valueTab = (xmlXPathObjectPtr *)
10911 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10912 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010913 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010914 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010915 }
10916 ctxt->valueNr = 0;
10917 ctxt->valueMax = 10;
10918 ctxt->value = NULL;
10919 }
10920 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010921 if(comp->last < 0) {
10922 xmlGenericError(xmlGenericErrorContext,
10923 "xmlXPathRunEval: last is less than zero\n");
10924 return;
10925 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010926 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10927}
10928
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010929/************************************************************************
10930 * *
10931 * Public interfaces *
10932 * *
10933 ************************************************************************/
10934
10935/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010936 * xmlXPathEvalPredicate:
10937 * @ctxt: the XPath context
10938 * @res: the Predicate Expression evaluation result
10939 *
10940 * Evaluate a predicate result for the current node.
10941 * A PredicateExpr is evaluated by evaluating the Expr and converting
10942 * the result to a boolean. If the result is a number, the result will
10943 * be converted to true if the number is equal to the position of the
10944 * context node in the context node list (as returned by the position
10945 * function) and will be converted to false otherwise; if the result
10946 * is not a number, then the result will be converted as if by a call
10947 * to the boolean function.
10948 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010949 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010950 */
10951int
10952xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000010953 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010954 switch (res->type) {
10955 case XPATH_BOOLEAN:
10956 return(res->boolval);
10957 case XPATH_NUMBER:
10958 return(res->floatval == ctxt->proximityPosition);
10959 case XPATH_NODESET:
10960 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010961 if (res->nodesetval == NULL)
10962 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010963 return(res->nodesetval->nodeNr != 0);
10964 case XPATH_STRING:
10965 return((res->stringval != NULL) &&
10966 (xmlStrlen(res->stringval) != 0));
10967 default:
10968 STRANGE
10969 }
10970 return(0);
10971}
10972
10973/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010974 * xmlXPathEvaluatePredicateResult:
10975 * @ctxt: the XPath Parser context
10976 * @res: the Predicate Expression evaluation result
10977 *
10978 * Evaluate a predicate result for the current node.
10979 * A PredicateExpr is evaluated by evaluating the Expr and converting
10980 * the result to a boolean. If the result is a number, the result will
10981 * be converted to true if the number is equal to the position of the
10982 * context node in the context node list (as returned by the position
10983 * function) and will be converted to false otherwise; if the result
10984 * is not a number, then the result will be converted as if by a call
10985 * to the boolean function.
10986 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010987 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010988 */
10989int
10990xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10991 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000010992 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010993 switch (res->type) {
10994 case XPATH_BOOLEAN:
10995 return(res->boolval);
10996 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000010997#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000010998 return((res->floatval == ctxt->context->proximityPosition) &&
10999 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000011000#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011001 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000011002#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011003 case XPATH_NODESET:
11004 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000011005 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000011006 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011007 return(res->nodesetval->nodeNr != 0);
11008 case XPATH_STRING:
11009 return((res->stringval != NULL) &&
11010 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000011011#ifdef LIBXML_XPTR_ENABLED
11012 case XPATH_LOCATIONSET:{
11013 xmlLocationSetPtr ptr = res->user;
11014 if (ptr == NULL)
11015 return(0);
11016 return (ptr->locNr != 0);
11017 }
11018#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011019 default:
11020 STRANGE
11021 }
11022 return(0);
11023}
11024
11025/**
Daniel Veillard4773df22004-01-23 13:15:13 +000011026 * xmlXPathCtxtCompile:
11027 * @ctxt: an XPath context
11028 * @str: the XPath expression
11029 *
11030 * Compile an XPath expression
11031 *
11032 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
11033 * the caller has to free the object.
11034 */
11035xmlXPathCompExprPtr
11036xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11037 xmlXPathParserContextPtr pctxt;
11038 xmlXPathCompExprPtr comp;
11039
11040 xmlXPathInit();
11041
11042 pctxt = xmlXPathNewParserContext(str, ctxt);
11043 xmlXPathCompileExpr(pctxt);
11044
11045 if( pctxt->error != XPATH_EXPRESSION_OK )
11046 {
11047 xmlXPathFreeParserContext(pctxt);
11048 return (0);
11049 }
11050
11051 if (*pctxt->cur != 0) {
11052 /*
11053 * aleksey: in some cases this line prints *second* error message
11054 * (see bug #78858) and probably this should be fixed.
11055 * However, we are not sure that all error messages are printed
11056 * out in other places. It's not critical so we leave it as-is for now
11057 */
11058 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11059 comp = NULL;
11060 } else {
11061 comp = pctxt->comp;
11062 pctxt->comp = NULL;
11063 }
11064 xmlXPathFreeParserContext(pctxt);
11065 if (comp != NULL) {
11066 comp->expr = xmlStrdup(str);
11067#ifdef DEBUG_EVAL_COUNTS
11068 comp->string = xmlStrdup(str);
11069 comp->nb = 0;
11070#endif
11071 }
11072 return(comp);
11073}
11074
11075/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011076 * xmlXPathCompile:
11077 * @str: the XPath expression
11078 *
11079 * Compile an XPath expression
11080 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000011081 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011082 * the caller has to free the object.
11083 */
11084xmlXPathCompExprPtr
11085xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000011086 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011087}
11088
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011089/**
11090 * xmlXPathCompiledEval:
11091 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000011092 * @ctx: the XPath context
11093 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011094 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000011095 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011096 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000011097 * the caller has to free the object.
11098 */
11099xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011100xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000011101 xmlXPathParserContextPtr ctxt;
11102 xmlXPathObjectPtr res, tmp, init = NULL;
11103 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000011104#ifndef LIBXML_THREAD_ENABLED
11105 static int reentance = 0;
11106#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011107
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011108 if ((comp == NULL) || (ctx == NULL))
11109 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011110 xmlXPathInit();
11111
11112 CHECK_CONTEXT(ctx)
11113
Daniel Veillard81463942001-10-16 12:34:39 +000011114#ifndef LIBXML_THREAD_ENABLED
11115 reentance++;
11116 if (reentance > 1)
11117 xmlXPathDisableOptimizer = 1;
11118#endif
11119
Daniel Veillardf06307e2001-07-03 10:35:50 +000011120#ifdef DEBUG_EVAL_COUNTS
11121 comp->nb++;
11122 if ((comp->string != NULL) && (comp->nb > 100)) {
11123 fprintf(stderr, "100 x %s\n", comp->string);
11124 comp->nb = 0;
11125 }
11126#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011127 ctxt = xmlXPathCompParserContext(comp, ctx);
11128 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011129
11130 if (ctxt->value == NULL) {
11131 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011132 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011133 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011134 } else {
11135 res = valuePop(ctxt);
11136 }
11137
Daniel Veillardf06307e2001-07-03 10:35:50 +000011138
Owen Taylor3473f882001-02-23 17:55:21 +000011139 do {
11140 tmp = valuePop(ctxt);
11141 if (tmp != NULL) {
11142 if (tmp != init)
11143 stack++;
11144 xmlXPathFreeObject(tmp);
11145 }
11146 } while (tmp != NULL);
11147 if ((stack != 0) && (res != NULL)) {
11148 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011149 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011150 stack);
11151 }
11152 if (ctxt->error != XPATH_EXPRESSION_OK) {
11153 xmlXPathFreeObject(res);
11154 res = NULL;
11155 }
11156
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011157
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011158 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011159 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011160#ifndef LIBXML_THREAD_ENABLED
11161 reentance--;
11162#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011163 return(res);
11164}
11165
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011166/**
11167 * xmlXPathEvalExpr:
11168 * @ctxt: the XPath Parser context
11169 *
11170 * Parse and evaluate an XPath expression in the given context,
11171 * then push the result on the context stack
11172 */
11173void
11174xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +000011175 if (ctxt == NULL) return;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011176 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011177 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011178 xmlXPathRunEval(ctxt);
11179}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011180
11181/**
11182 * xmlXPathEval:
11183 * @str: the XPath expression
11184 * @ctx: the XPath context
11185 *
11186 * Evaluate the XPath Location Path in the given context.
11187 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011188 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011189 * the caller has to free the object.
11190 */
11191xmlXPathObjectPtr
11192xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11193 xmlXPathParserContextPtr ctxt;
11194 xmlXPathObjectPtr res, tmp, init = NULL;
11195 int stack = 0;
11196
11197 xmlXPathInit();
11198
11199 CHECK_CONTEXT(ctx)
11200
11201 ctxt = xmlXPathNewParserContext(str, ctx);
11202 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011203
11204 if (ctxt->value == NULL) {
11205 xmlGenericError(xmlGenericErrorContext,
11206 "xmlXPathEval: evaluation failed\n");
11207 res = NULL;
11208 } else if (*ctxt->cur != 0) {
11209 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11210 res = NULL;
11211 } else {
11212 res = valuePop(ctxt);
11213 }
11214
11215 do {
11216 tmp = valuePop(ctxt);
11217 if (tmp != NULL) {
11218 if (tmp != init)
11219 stack++;
11220 xmlXPathFreeObject(tmp);
11221 }
11222 } while (tmp != NULL);
11223 if ((stack != 0) && (res != NULL)) {
11224 xmlGenericError(xmlGenericErrorContext,
11225 "xmlXPathEval: %d object left on the stack\n",
11226 stack);
11227 }
11228 if (ctxt->error != XPATH_EXPRESSION_OK) {
11229 xmlXPathFreeObject(res);
11230 res = NULL;
11231 }
11232
Owen Taylor3473f882001-02-23 17:55:21 +000011233 xmlXPathFreeParserContext(ctxt);
11234 return(res);
11235}
11236
11237/**
11238 * xmlXPathEvalExpression:
11239 * @str: the XPath expression
11240 * @ctxt: the XPath context
11241 *
11242 * Evaluate the XPath expression in the given context.
11243 *
11244 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11245 * the caller has to free the object.
11246 */
11247xmlXPathObjectPtr
11248xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11249 xmlXPathParserContextPtr pctxt;
11250 xmlXPathObjectPtr res, tmp;
11251 int stack = 0;
11252
11253 xmlXPathInit();
11254
11255 CHECK_CONTEXT(ctxt)
11256
11257 pctxt = xmlXPathNewParserContext(str, ctxt);
11258 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011259
11260 if (*pctxt->cur != 0) {
11261 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11262 res = NULL;
11263 } else {
11264 res = valuePop(pctxt);
11265 }
11266 do {
11267 tmp = valuePop(pctxt);
11268 if (tmp != NULL) {
11269 xmlXPathFreeObject(tmp);
11270 stack++;
11271 }
11272 } while (tmp != NULL);
11273 if ((stack != 0) && (res != NULL)) {
11274 xmlGenericError(xmlGenericErrorContext,
11275 "xmlXPathEvalExpression: %d object left on the stack\n",
11276 stack);
11277 }
11278 xmlXPathFreeParserContext(pctxt);
11279 return(res);
11280}
11281
Daniel Veillard42766c02002-08-22 20:52:17 +000011282/************************************************************************
11283 * *
11284 * Extra functions not pertaining to the XPath spec *
11285 * *
11286 ************************************************************************/
11287/**
11288 * xmlXPathEscapeUriFunction:
11289 * @ctxt: the XPath Parser context
11290 * @nargs: the number of arguments
11291 *
11292 * Implement the escape-uri() XPath function
11293 * string escape-uri(string $str, bool $escape-reserved)
11294 *
11295 * This function applies the URI escaping rules defined in section 2 of [RFC
11296 * 2396] to the string supplied as $uri-part, which typically represents all
11297 * or part of a URI. The effect of the function is to replace any special
11298 * character in the string by an escape sequence of the form %xx%yy...,
11299 * where xxyy... is the hexadecimal representation of the octets used to
11300 * represent the character in UTF-8.
11301 *
11302 * The set of characters that are escaped depends on the setting of the
11303 * boolean argument $escape-reserved.
11304 *
11305 * If $escape-reserved is true, all characters are escaped other than lower
11306 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11307 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11308 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11309 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11310 * A-F).
11311 *
11312 * If $escape-reserved is false, the behavior differs in that characters
11313 * referred to in [RFC 2396] as reserved characters are not escaped. These
11314 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11315 *
11316 * [RFC 2396] does not define whether escaped URIs should use lower case or
11317 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11318 * compared using string comparison functions, this function must always use
11319 * the upper-case letters A-F.
11320 *
11321 * Generally, $escape-reserved should be set to true when escaping a string
11322 * that is to form a single part of a URI, and to false when escaping an
11323 * entire URI or URI reference.
11324 *
11325 * In the case of non-ascii characters, the string is encoded according to
11326 * utf-8 and then converted according to RFC 2396.
11327 *
11328 * Examples
11329 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11330 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11331 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11332 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11333 *
11334 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011335static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011336xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11337 xmlXPathObjectPtr str;
11338 int escape_reserved;
11339 xmlBufferPtr target;
11340 xmlChar *cptr;
11341 xmlChar escape[4];
11342
11343 CHECK_ARITY(2);
11344
11345 escape_reserved = xmlXPathPopBoolean(ctxt);
11346
11347 CAST_TO_STRING;
11348 str = valuePop(ctxt);
11349
11350 target = xmlBufferCreate();
11351
11352 escape[0] = '%';
11353 escape[3] = 0;
11354
11355 if (target) {
11356 for (cptr = str->stringval; *cptr; cptr++) {
11357 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11358 (*cptr >= 'a' && *cptr <= 'z') ||
11359 (*cptr >= '0' && *cptr <= '9') ||
11360 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11361 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11362 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11363 (*cptr == '%' &&
11364 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11365 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11366 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11367 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11368 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11369 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11370 (!escape_reserved &&
11371 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11372 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11373 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11374 *cptr == ','))) {
11375 xmlBufferAdd(target, cptr, 1);
11376 } else {
11377 if ((*cptr >> 4) < 10)
11378 escape[1] = '0' + (*cptr >> 4);
11379 else
11380 escape[1] = 'A' - 10 + (*cptr >> 4);
11381 if ((*cptr & 0xF) < 10)
11382 escape[2] = '0' + (*cptr & 0xF);
11383 else
11384 escape[2] = 'A' - 10 + (*cptr & 0xF);
11385
11386 xmlBufferAdd(target, &escape[0], 3);
11387 }
11388 }
11389 }
11390 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11391 xmlBufferFree(target);
11392 xmlXPathFreeObject(str);
11393}
11394
Owen Taylor3473f882001-02-23 17:55:21 +000011395/**
11396 * xmlXPathRegisterAllFunctions:
11397 * @ctxt: the XPath context
11398 *
11399 * Registers all default XPath functions in this context
11400 */
11401void
11402xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11403{
11404 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11405 xmlXPathBooleanFunction);
11406 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11407 xmlXPathCeilingFunction);
11408 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11409 xmlXPathCountFunction);
11410 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11411 xmlXPathConcatFunction);
11412 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11413 xmlXPathContainsFunction);
11414 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11415 xmlXPathIdFunction);
11416 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11417 xmlXPathFalseFunction);
11418 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11419 xmlXPathFloorFunction);
11420 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11421 xmlXPathLastFunction);
11422 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11423 xmlXPathLangFunction);
11424 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11425 xmlXPathLocalNameFunction);
11426 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11427 xmlXPathNotFunction);
11428 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11429 xmlXPathNameFunction);
11430 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11431 xmlXPathNamespaceURIFunction);
11432 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11433 xmlXPathNormalizeFunction);
11434 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11435 xmlXPathNumberFunction);
11436 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11437 xmlXPathPositionFunction);
11438 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11439 xmlXPathRoundFunction);
11440 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11441 xmlXPathStringFunction);
11442 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11443 xmlXPathStringLengthFunction);
11444 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11445 xmlXPathStartsWithFunction);
11446 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11447 xmlXPathSubstringFunction);
11448 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11449 xmlXPathSubstringBeforeFunction);
11450 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11451 xmlXPathSubstringAfterFunction);
11452 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11453 xmlXPathSumFunction);
11454 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11455 xmlXPathTrueFunction);
11456 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11457 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011458
11459 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11460 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11461 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011462}
11463
11464#endif /* LIBXML_XPATH_ENABLED */