blob: 9eb0b486f17cbd680a04e7f4741479b9e0f8f429 [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>
Daniel Veillard56de87e2005-02-16 00:22:29 +000054#ifdef LIBXML_PATTERN_ENABLED
55#include <libxml/pattern.h>
56#endif
57
58#ifdef LIBXML_PATTERN_ENABLED
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000059#define XPATH_STREAMING
Daniel Veillard56de87e2005-02-16 00:22:29 +000060#endif
Owen Taylor3473f882001-02-23 17:55:21 +000061
Daniel Veillardd96f6d32003-10-07 21:25:12 +000062#define TODO \
63 xmlGenericError(xmlGenericErrorContext, \
64 "Unimplemented block at %s:%d\n", \
65 __FILE__, __LINE__);
66
William M. Brackd1757ab2004-10-02 22:07:48 +000067/*
68 * TODO:
69 * There are a few spots where some tests are done which depend upon ascii
70 * data. These should be enhanced for full UTF8 support (see particularly
71 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
72 */
73
William M. Brack21e4ef22005-01-02 09:53:13 +000074#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000075/************************************************************************
76 * *
77 * Floating point stuff *
78 * *
79 ************************************************************************/
80
Daniel Veillardc0631a62001-09-20 13:56:06 +000081#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000082#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000083#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000084#include "trionan.c"
85
Owen Taylor3473f882001-02-23 17:55:21 +000086/*
Owen Taylor3473f882001-02-23 17:55:21 +000087 * The lack of portability of this section of the libc is annoying !
88 */
89double xmlXPathNAN = 0;
90double xmlXPathPINF = 1;
91double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000092double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000093static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000094
Owen Taylor3473f882001-02-23 17:55:21 +000095/**
96 * xmlXPathInit:
97 *
98 * Initialize the XPath environment
99 */
100void
101xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000102 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000103
Bjorn Reese45029602001-08-21 09:23:53 +0000104 xmlXPathPINF = trio_pinf();
105 xmlXPathNINF = trio_ninf();
106 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000107 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000108
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000109 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000110}
111
Daniel Veillardcda96922001-08-21 10:56:31 +0000112/**
113 * xmlXPathIsNaN:
114 * @val: a double value
115 *
116 * Provides a portable isnan() function to detect whether a double
117 * is a NotaNumber. Based on trio code
118 * http://sourceforge.net/projects/ctrio/
119 *
120 * Returns 1 if the value is a NaN, 0 otherwise
121 */
122int
123xmlXPathIsNaN(double val) {
124 return(trio_isnan(val));
125}
126
127/**
128 * xmlXPathIsInf:
129 * @val: a double value
130 *
131 * Provides a portable isinf() function to detect whether a double
132 * is a +Infinite or -Infinite. Based on trio code
133 * http://sourceforge.net/projects/ctrio/
134 *
135 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
136 */
137int
138xmlXPathIsInf(double val) {
139 return(trio_isinf(val));
140}
141
Daniel Veillard4432df22003-09-28 18:58:27 +0000142#endif /* SCHEMAS or XPATH */
143#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000144/**
145 * xmlXPathGetSign:
146 * @val: a double value
147 *
148 * Provides a portable function to detect the sign of a double
149 * Modified from trio code
150 * http://sourceforge.net/projects/ctrio/
151 *
152 * Returns 1 if the value is Negative, 0 if positive
153 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000154static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000155xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000156 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000157}
158
159
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000160/*
161 * TODO: when compatibility allows remove all "fake node libxslt" strings
162 * the test should just be name[0] = ' '
163 */
164/* #define DEBUG */
165/* #define DEBUG_STEP */
166/* #define DEBUG_STEP_NTH */
167/* #define DEBUG_EXPR */
168/* #define DEBUG_EVAL_COUNTS */
169
170static xmlNs xmlXPathXMLNamespaceStruct = {
171 NULL,
172 XML_NAMESPACE_DECL,
173 XML_XML_NAMESPACE,
174 BAD_CAST "xml",
175 NULL
176};
177static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
178#ifndef LIBXML_THREAD_ENABLED
179/*
180 * Optimizer is disabled only when threaded apps are detected while
181 * the library ain't compiled for thread safety.
182 */
183static int xmlXPathDisableOptimizer = 0;
184#endif
185
Owen Taylor3473f882001-02-23 17:55:21 +0000186/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000187 * *
188 * Error handling routines *
189 * *
190 ************************************************************************/
191
William M. Brack08171912003-12-29 02:52:11 +0000192/*
193 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
194 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000195static const char *xmlXPathErrorMessages[] = {
196 "Ok\n",
197 "Number encoding\n",
198 "Unfinished literal\n",
199 "Start of literal\n",
200 "Expected $ for variable reference\n",
201 "Undefined variable\n",
202 "Invalid predicate\n",
203 "Invalid expression\n",
204 "Missing closing curly brace\n",
205 "Unregistered function\n",
206 "Invalid operand\n",
207 "Invalid type\n",
208 "Invalid number of arguments\n",
209 "Invalid context size\n",
210 "Invalid context position\n",
211 "Memory allocation error\n",
212 "Syntax error\n",
213 "Resource error\n",
214 "Sub resource error\n",
215 "Undefined namespace prefix\n",
216 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000217 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000218 "Invalid or incomplete context\n",
219 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000220};
William M. Brackcd65bc92005-01-06 09:39:18 +0000221#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
222 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000223/**
224 * xmlXPathErrMemory:
225 * @ctxt: an XPath context
226 * @extra: extra informations
227 *
228 * Handle a redefinition of attribute error
229 */
230static void
231xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
232{
233 if (ctxt != NULL) {
234 if (extra) {
235 xmlChar buf[200];
236
237 xmlStrPrintf(buf, 200,
238 BAD_CAST "Memory allocation failed : %s\n",
239 extra);
240 ctxt->lastError.message = (char *) xmlStrdup(buf);
241 } else {
242 ctxt->lastError.message = (char *)
243 xmlStrdup(BAD_CAST "Memory allocation failed\n");
244 }
245 ctxt->lastError.domain = XML_FROM_XPATH;
246 ctxt->lastError.code = XML_ERR_NO_MEMORY;
247 if (ctxt->error != NULL)
248 ctxt->error(ctxt->userData, &ctxt->lastError);
249 } else {
250 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000251 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000252 NULL, NULL, XML_FROM_XPATH,
253 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
254 extra, NULL, NULL, 0, 0,
255 "Memory allocation failed : %s\n", extra);
256 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000257 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000258 NULL, NULL, XML_FROM_XPATH,
259 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
260 NULL, NULL, NULL, 0, 0,
261 "Memory allocation failed\n");
262 }
263}
264
265/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000266 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000267 * @ctxt: an XPath parser context
268 * @extra: extra informations
269 *
270 * Handle a redefinition of attribute error
271 */
272static void
273xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
274{
275 ctxt->error = XPATH_MEMORY_ERROR;
276 if (ctxt == NULL)
277 xmlXPathErrMemory(NULL, extra);
278 else
279 xmlXPathErrMemory(ctxt->context, extra);
280}
281
282/**
283 * xmlXPathErr:
284 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000285 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000286 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000287 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000288 */
289void
290xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
291{
William M. Brackcd65bc92005-01-06 09:39:18 +0000292 if ((error < 0) || (error > MAXERRNO))
293 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000294 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000295 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000296 NULL, NULL, XML_FROM_XPATH,
297 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
298 XML_ERR_ERROR, NULL, 0,
299 NULL, NULL, NULL, 0, 0,
300 xmlXPathErrorMessages[error]);
301 return;
302 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000303 ctxt->error = error;
304 if (ctxt->context == NULL) {
305 __xmlRaiseError(NULL, NULL, NULL,
306 NULL, NULL, XML_FROM_XPATH,
307 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
308 XML_ERR_ERROR, NULL, 0,
309 (const char *) ctxt->base, NULL, NULL,
310 ctxt->cur - ctxt->base, 0,
311 xmlXPathErrorMessages[error]);
312 return;
313 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000314 ctxt->context->lastError.domain = XML_FROM_XPATH;
315 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
316 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000317 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000318 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
319 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
320 ctxt->context->lastError.node = ctxt->context->debugNode;
321 if (ctxt->context->error != NULL) {
322 ctxt->context->error(ctxt->context->userData,
323 &ctxt->context->lastError);
324 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000325 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000326 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
327 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
328 XML_ERR_ERROR, NULL, 0,
329 (const char *) ctxt->base, NULL, NULL,
330 ctxt->cur - ctxt->base, 0,
331 xmlXPathErrorMessages[error]);
332 }
333
334}
335
336/**
337 * xmlXPatherror:
338 * @ctxt: the XPath Parser context
339 * @file: the file name
340 * @line: the line number
341 * @no: the error number
342 *
343 * Formats an error message.
344 */
345void
346xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
347 int line ATTRIBUTE_UNUSED, int no) {
348 xmlXPathErr(ctxt, no);
349}
350
351
352/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000353 * *
354 * Parser Types *
355 * *
356 ************************************************************************/
357
358/*
359 * Types are private:
360 */
361
362typedef enum {
363 XPATH_OP_END=0,
364 XPATH_OP_AND,
365 XPATH_OP_OR,
366 XPATH_OP_EQUAL,
367 XPATH_OP_CMP,
368 XPATH_OP_PLUS,
369 XPATH_OP_MULT,
370 XPATH_OP_UNION,
371 XPATH_OP_ROOT,
372 XPATH_OP_NODE,
373 XPATH_OP_RESET,
374 XPATH_OP_COLLECT,
375 XPATH_OP_VALUE,
376 XPATH_OP_VARIABLE,
377 XPATH_OP_FUNCTION,
378 XPATH_OP_ARG,
379 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000380 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000381 XPATH_OP_SORT
382#ifdef LIBXML_XPTR_ENABLED
383 ,XPATH_OP_RANGETO
384#endif
385} xmlXPathOp;
386
387typedef enum {
388 AXIS_ANCESTOR = 1,
389 AXIS_ANCESTOR_OR_SELF,
390 AXIS_ATTRIBUTE,
391 AXIS_CHILD,
392 AXIS_DESCENDANT,
393 AXIS_DESCENDANT_OR_SELF,
394 AXIS_FOLLOWING,
395 AXIS_FOLLOWING_SIBLING,
396 AXIS_NAMESPACE,
397 AXIS_PARENT,
398 AXIS_PRECEDING,
399 AXIS_PRECEDING_SIBLING,
400 AXIS_SELF
401} xmlXPathAxisVal;
402
403typedef enum {
404 NODE_TEST_NONE = 0,
405 NODE_TEST_TYPE = 1,
406 NODE_TEST_PI = 2,
407 NODE_TEST_ALL = 3,
408 NODE_TEST_NS = 4,
409 NODE_TEST_NAME = 5
410} xmlXPathTestVal;
411
412typedef enum {
413 NODE_TYPE_NODE = 0,
414 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
415 NODE_TYPE_TEXT = XML_TEXT_NODE,
416 NODE_TYPE_PI = XML_PI_NODE
417} xmlXPathTypeVal;
418
419
420typedef struct _xmlXPathStepOp xmlXPathStepOp;
421typedef xmlXPathStepOp *xmlXPathStepOpPtr;
422struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000423 xmlXPathOp op; /* The identifier of the operation */
424 int ch1; /* First child */
425 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000426 int value;
427 int value2;
428 int value3;
429 void *value4;
430 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000431 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000432 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000433};
434
435struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000436 int nbStep; /* Number of steps in this expression */
437 int maxStep; /* Maximum number of steps allocated */
438 xmlXPathStepOp *steps; /* ops for computation of this expression */
439 int last; /* index of last step in expression */
440 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000441 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000442#ifdef DEBUG_EVAL_COUNTS
443 int nb;
444 xmlChar *string;
445#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000446#ifdef XPATH_STREAMING
447 xmlPatternPtr stream;
448#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000449};
450
451/************************************************************************
452 * *
453 * Parser Type functions *
454 * *
455 ************************************************************************/
456
457/**
458 * xmlXPathNewCompExpr:
459 *
460 * Create a new Xpath component
461 *
462 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
463 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000464static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000465xmlXPathNewCompExpr(void) {
466 xmlXPathCompExprPtr cur;
467
468 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
469 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000470 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000471 return(NULL);
472 }
473 memset(cur, 0, sizeof(xmlXPathCompExpr));
474 cur->maxStep = 10;
475 cur->nbStep = 0;
476 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
477 sizeof(xmlXPathStepOp));
478 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000479 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000480 xmlFree(cur);
481 return(NULL);
482 }
483 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
484 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000485#ifdef DEBUG_EVAL_COUNTS
486 cur->nb = 0;
487#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000488 return(cur);
489}
490
491/**
492 * xmlXPathFreeCompExpr:
493 * @comp: an XPATH comp
494 *
495 * Free up the memory allocated by @comp
496 */
497void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000498xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
499{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000500 xmlXPathStepOpPtr op;
501 int i;
502
503 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000504 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000505 if (comp->dict == NULL) {
506 for (i = 0; i < comp->nbStep; i++) {
507 op = &comp->steps[i];
508 if (op->value4 != NULL) {
509 if (op->op == XPATH_OP_VALUE)
510 xmlXPathFreeObject(op->value4);
511 else
512 xmlFree(op->value4);
513 }
514 if (op->value5 != NULL)
515 xmlFree(op->value5);
516 }
517 } else {
518 for (i = 0; i < comp->nbStep; i++) {
519 op = &comp->steps[i];
520 if (op->value4 != NULL) {
521 if (op->op == XPATH_OP_VALUE)
522 xmlXPathFreeObject(op->value4);
523 }
524 }
525 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000526 }
527 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000528 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000529 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000530#ifdef DEBUG_EVAL_COUNTS
531 if (comp->string != NULL) {
532 xmlFree(comp->string);
533 }
534#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000535#ifdef XPATH_STREAMING
536 if (comp->stream != NULL) {
537 xmlFreePatternList(comp->stream);
538 }
539#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000540 if (comp->expr != NULL) {
541 xmlFree(comp->expr);
542 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000543
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000544 xmlFree(comp);
545}
546
547/**
548 * xmlXPathCompExprAdd:
549 * @comp: the compiled expression
550 * @ch1: first child index
551 * @ch2: second child index
552 * @op: an op
553 * @value: the first int value
554 * @value2: the second int value
555 * @value3: the third int value
556 * @value4: the first string value
557 * @value5: the second string value
558 *
William M. Brack08171912003-12-29 02:52:11 +0000559 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000560 *
561 * Returns -1 in case of failure, the index otherwise
562 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000563static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000564xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
565 xmlXPathOp op, int value,
566 int value2, int value3, void *value4, void *value5) {
567 if (comp->nbStep >= comp->maxStep) {
568 xmlXPathStepOp *real;
569
570 comp->maxStep *= 2;
571 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
572 comp->maxStep * sizeof(xmlXPathStepOp));
573 if (real == NULL) {
574 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000575 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000576 return(-1);
577 }
578 comp->steps = real;
579 }
580 comp->last = comp->nbStep;
581 comp->steps[comp->nbStep].ch1 = ch1;
582 comp->steps[comp->nbStep].ch2 = ch2;
583 comp->steps[comp->nbStep].op = op;
584 comp->steps[comp->nbStep].value = value;
585 comp->steps[comp->nbStep].value2 = value2;
586 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000587 if ((comp->dict != NULL) &&
588 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
589 (op == XPATH_OP_COLLECT))) {
590 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000591 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000592 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000593 xmlFree(value4);
594 } else
595 comp->steps[comp->nbStep].value4 = NULL;
596 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000597 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000598 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000599 xmlFree(value5);
600 } else
601 comp->steps[comp->nbStep].value5 = NULL;
602 } else {
603 comp->steps[comp->nbStep].value4 = value4;
604 comp->steps[comp->nbStep].value5 = value5;
605 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000606 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000607 return(comp->nbStep++);
608}
609
Daniel Veillardf06307e2001-07-03 10:35:50 +0000610/**
611 * xmlXPathCompSwap:
612 * @comp: the compiled expression
613 * @op: operation index
614 *
615 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000616 */
617static void
618xmlXPathCompSwap(xmlXPathStepOpPtr op) {
619 int tmp;
620
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000621#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000622 /*
623 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000624 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000625 * application
626 */
627 if (xmlXPathDisableOptimizer)
628 return;
629#endif
630
Daniel Veillardf06307e2001-07-03 10:35:50 +0000631 tmp = op->ch1;
632 op->ch1 = op->ch2;
633 op->ch2 = tmp;
634}
635
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000636#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
637 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
638 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000639#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
640 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
641 (op), (val), (val2), (val3), (val4), (val5))
642
643#define PUSH_LEAVE_EXPR(op, val, val2) \
644xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
645
646#define PUSH_UNARY_EXPR(op, ch, val, val2) \
647xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
648
649#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000650xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
651 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000652
653/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000654 * *
655 * Debugging related functions *
656 * *
657 ************************************************************************/
658
Owen Taylor3473f882001-02-23 17:55:21 +0000659#define STRANGE \
660 xmlGenericError(xmlGenericErrorContext, \
661 "Internal error at %s:%d\n", \
662 __FILE__, __LINE__);
663
664#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000665static void
666xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000667 int i;
668 char shift[100];
669
670 for (i = 0;((i < depth) && (i < 25));i++)
671 shift[2 * i] = shift[2 * i + 1] = ' ';
672 shift[2 * i] = shift[2 * i + 1] = 0;
673 if (cur == NULL) {
674 fprintf(output, shift);
675 fprintf(output, "Node is NULL !\n");
676 return;
677
678 }
679
680 if ((cur->type == XML_DOCUMENT_NODE) ||
681 (cur->type == XML_HTML_DOCUMENT_NODE)) {
682 fprintf(output, shift);
683 fprintf(output, " /\n");
684 } else if (cur->type == XML_ATTRIBUTE_NODE)
685 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
686 else
687 xmlDebugDumpOneNode(output, cur, depth);
688}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000689static void
690xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000691 xmlNodePtr tmp;
692 int i;
693 char shift[100];
694
695 for (i = 0;((i < depth) && (i < 25));i++)
696 shift[2 * i] = shift[2 * i + 1] = ' ';
697 shift[2 * i] = shift[2 * i + 1] = 0;
698 if (cur == NULL) {
699 fprintf(output, shift);
700 fprintf(output, "Node is NULL !\n");
701 return;
702
703 }
704
705 while (cur != NULL) {
706 tmp = cur;
707 cur = cur->next;
708 xmlDebugDumpOneNode(output, tmp, depth);
709 }
710}
Owen Taylor3473f882001-02-23 17:55:21 +0000711
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000712static void
713xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000714 int i;
715 char shift[100];
716
717 for (i = 0;((i < depth) && (i < 25));i++)
718 shift[2 * i] = shift[2 * i + 1] = ' ';
719 shift[2 * i] = shift[2 * i + 1] = 0;
720
721 if (cur == NULL) {
722 fprintf(output, shift);
723 fprintf(output, "NodeSet is NULL !\n");
724 return;
725
726 }
727
Daniel Veillard911f49a2001-04-07 15:39:35 +0000728 if (cur != NULL) {
729 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
730 for (i = 0;i < cur->nodeNr;i++) {
731 fprintf(output, shift);
732 fprintf(output, "%d", i + 1);
733 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
734 }
Owen Taylor3473f882001-02-23 17:55:21 +0000735 }
736}
737
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000738static void
739xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000740 int i;
741 char shift[100];
742
743 for (i = 0;((i < depth) && (i < 25));i++)
744 shift[2 * i] = shift[2 * i + 1] = ' ';
745 shift[2 * i] = shift[2 * i + 1] = 0;
746
747 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
748 fprintf(output, shift);
749 fprintf(output, "Value Tree is NULL !\n");
750 return;
751
752 }
753
754 fprintf(output, shift);
755 fprintf(output, "%d", i + 1);
756 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
757}
Owen Taylor3473f882001-02-23 17:55:21 +0000758#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000759static void
760xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000761 int i;
762 char shift[100];
763
764 for (i = 0;((i < depth) && (i < 25));i++)
765 shift[2 * i] = shift[2 * i + 1] = ' ';
766 shift[2 * i] = shift[2 * i + 1] = 0;
767
768 if (cur == NULL) {
769 fprintf(output, shift);
770 fprintf(output, "LocationSet is NULL !\n");
771 return;
772
773 }
774
775 for (i = 0;i < cur->locNr;i++) {
776 fprintf(output, shift);
777 fprintf(output, "%d : ", i + 1);
778 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
779 }
780}
Daniel Veillard017b1082001-06-21 11:20:21 +0000781#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000782
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000783/**
784 * xmlXPathDebugDumpObject:
785 * @output: the FILE * to dump the output
786 * @cur: the object to inspect
787 * @depth: indentation level
788 *
789 * Dump the content of the object for debugging purposes
790 */
791void
792xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000793 int i;
794 char shift[100];
795
Daniel Veillarda82b1822004-11-08 16:24:57 +0000796 if (output == NULL) return;
797
Owen Taylor3473f882001-02-23 17:55:21 +0000798 for (i = 0;((i < depth) && (i < 25));i++)
799 shift[2 * i] = shift[2 * i + 1] = ' ';
800 shift[2 * i] = shift[2 * i + 1] = 0;
801
802 fprintf(output, shift);
803
804 if (cur == NULL) {
805 fprintf(output, "Object is empty (NULL)\n");
806 return;
807 }
808 switch(cur->type) {
809 case XPATH_UNDEFINED:
810 fprintf(output, "Object is uninitialized\n");
811 break;
812 case XPATH_NODESET:
813 fprintf(output, "Object is a Node Set :\n");
814 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
815 break;
816 case XPATH_XSLT_TREE:
817 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000818 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000819 break;
820 case XPATH_BOOLEAN:
821 fprintf(output, "Object is a Boolean : ");
822 if (cur->boolval) fprintf(output, "true\n");
823 else fprintf(output, "false\n");
824 break;
825 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000826 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000827 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000828 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000829 break;
830 case -1:
831 fprintf(output, "Object is a number : -Infinity\n");
832 break;
833 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000834 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000835 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000836 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
837 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000838 } else {
839 fprintf(output, "Object is a number : %0g\n", cur->floatval);
840 }
841 }
Owen Taylor3473f882001-02-23 17:55:21 +0000842 break;
843 case XPATH_STRING:
844 fprintf(output, "Object is a string : ");
845 xmlDebugDumpString(output, cur->stringval);
846 fprintf(output, "\n");
847 break;
848 case XPATH_POINT:
849 fprintf(output, "Object is a point : index %d in node", cur->index);
850 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
851 fprintf(output, "\n");
852 break;
853 case XPATH_RANGE:
854 if ((cur->user2 == NULL) ||
855 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
856 fprintf(output, "Object is a collapsed range :\n");
857 fprintf(output, shift);
858 if (cur->index >= 0)
859 fprintf(output, "index %d in ", cur->index);
860 fprintf(output, "node\n");
861 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
862 depth + 1);
863 } else {
864 fprintf(output, "Object is a range :\n");
865 fprintf(output, shift);
866 fprintf(output, "From ");
867 if (cur->index >= 0)
868 fprintf(output, "index %d in ", cur->index);
869 fprintf(output, "node\n");
870 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
871 depth + 1);
872 fprintf(output, shift);
873 fprintf(output, "To ");
874 if (cur->index2 >= 0)
875 fprintf(output, "index %d in ", cur->index2);
876 fprintf(output, "node\n");
877 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
878 depth + 1);
879 fprintf(output, "\n");
880 }
881 break;
882 case XPATH_LOCATIONSET:
883#if defined(LIBXML_XPTR_ENABLED)
884 fprintf(output, "Object is a Location Set:\n");
885 xmlXPathDebugDumpLocationSet(output,
886 (xmlLocationSetPtr) cur->user, depth);
887#endif
888 break;
889 case XPATH_USERS:
890 fprintf(output, "Object is user defined\n");
891 break;
892 }
893}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000894
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000895static void
896xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000897 xmlXPathStepOpPtr op, int depth) {
898 int i;
899 char shift[100];
900
901 for (i = 0;((i < depth) && (i < 25));i++)
902 shift[2 * i] = shift[2 * i + 1] = ' ';
903 shift[2 * i] = shift[2 * i + 1] = 0;
904
905 fprintf(output, shift);
906 if (op == NULL) {
907 fprintf(output, "Step is NULL\n");
908 return;
909 }
910 switch (op->op) {
911 case XPATH_OP_END:
912 fprintf(output, "END"); break;
913 case XPATH_OP_AND:
914 fprintf(output, "AND"); break;
915 case XPATH_OP_OR:
916 fprintf(output, "OR"); break;
917 case XPATH_OP_EQUAL:
918 if (op->value)
919 fprintf(output, "EQUAL =");
920 else
921 fprintf(output, "EQUAL !=");
922 break;
923 case XPATH_OP_CMP:
924 if (op->value)
925 fprintf(output, "CMP <");
926 else
927 fprintf(output, "CMP >");
928 if (!op->value2)
929 fprintf(output, "=");
930 break;
931 case XPATH_OP_PLUS:
932 if (op->value == 0)
933 fprintf(output, "PLUS -");
934 else if (op->value == 1)
935 fprintf(output, "PLUS +");
936 else if (op->value == 2)
937 fprintf(output, "PLUS unary -");
938 else if (op->value == 3)
939 fprintf(output, "PLUS unary - -");
940 break;
941 case XPATH_OP_MULT:
942 if (op->value == 0)
943 fprintf(output, "MULT *");
944 else if (op->value == 1)
945 fprintf(output, "MULT div");
946 else
947 fprintf(output, "MULT mod");
948 break;
949 case XPATH_OP_UNION:
950 fprintf(output, "UNION"); break;
951 case XPATH_OP_ROOT:
952 fprintf(output, "ROOT"); break;
953 case XPATH_OP_NODE:
954 fprintf(output, "NODE"); break;
955 case XPATH_OP_RESET:
956 fprintf(output, "RESET"); break;
957 case XPATH_OP_SORT:
958 fprintf(output, "SORT"); break;
959 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000960 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
961 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
962 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000963 const xmlChar *prefix = op->value4;
964 const xmlChar *name = op->value5;
965
966 fprintf(output, "COLLECT ");
967 switch (axis) {
968 case AXIS_ANCESTOR:
969 fprintf(output, " 'ancestors' "); break;
970 case AXIS_ANCESTOR_OR_SELF:
971 fprintf(output, " 'ancestors-or-self' "); break;
972 case AXIS_ATTRIBUTE:
973 fprintf(output, " 'attributes' "); break;
974 case AXIS_CHILD:
975 fprintf(output, " 'child' "); break;
976 case AXIS_DESCENDANT:
977 fprintf(output, " 'descendant' "); break;
978 case AXIS_DESCENDANT_OR_SELF:
979 fprintf(output, " 'descendant-or-self' "); break;
980 case AXIS_FOLLOWING:
981 fprintf(output, " 'following' "); break;
982 case AXIS_FOLLOWING_SIBLING:
983 fprintf(output, " 'following-siblings' "); break;
984 case AXIS_NAMESPACE:
985 fprintf(output, " 'namespace' "); break;
986 case AXIS_PARENT:
987 fprintf(output, " 'parent' "); break;
988 case AXIS_PRECEDING:
989 fprintf(output, " 'preceding' "); break;
990 case AXIS_PRECEDING_SIBLING:
991 fprintf(output, " 'preceding-sibling' "); break;
992 case AXIS_SELF:
993 fprintf(output, " 'self' "); break;
994 }
995 switch (test) {
996 case NODE_TEST_NONE:
997 fprintf(output, "'none' "); break;
998 case NODE_TEST_TYPE:
999 fprintf(output, "'type' "); break;
1000 case NODE_TEST_PI:
1001 fprintf(output, "'PI' "); break;
1002 case NODE_TEST_ALL:
1003 fprintf(output, "'all' "); break;
1004 case NODE_TEST_NS:
1005 fprintf(output, "'namespace' "); break;
1006 case NODE_TEST_NAME:
1007 fprintf(output, "'name' "); break;
1008 }
1009 switch (type) {
1010 case NODE_TYPE_NODE:
1011 fprintf(output, "'node' "); break;
1012 case NODE_TYPE_COMMENT:
1013 fprintf(output, "'comment' "); break;
1014 case NODE_TYPE_TEXT:
1015 fprintf(output, "'text' "); break;
1016 case NODE_TYPE_PI:
1017 fprintf(output, "'PI' "); break;
1018 }
1019 if (prefix != NULL)
1020 fprintf(output, "%s:", prefix);
1021 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001022 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001023 break;
1024
1025 }
1026 case XPATH_OP_VALUE: {
1027 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1028
1029 fprintf(output, "ELEM ");
1030 xmlXPathDebugDumpObject(output, object, 0);
1031 goto finish;
1032 }
1033 case XPATH_OP_VARIABLE: {
1034 const xmlChar *prefix = op->value5;
1035 const xmlChar *name = op->value4;
1036
1037 if (prefix != NULL)
1038 fprintf(output, "VARIABLE %s:%s", prefix, name);
1039 else
1040 fprintf(output, "VARIABLE %s", name);
1041 break;
1042 }
1043 case XPATH_OP_FUNCTION: {
1044 int nbargs = op->value;
1045 const xmlChar *prefix = op->value5;
1046 const xmlChar *name = op->value4;
1047
1048 if (prefix != NULL)
1049 fprintf(output, "FUNCTION %s:%s(%d args)",
1050 prefix, name, nbargs);
1051 else
1052 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1053 break;
1054 }
1055 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1056 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001057 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001058#ifdef LIBXML_XPTR_ENABLED
1059 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1060#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001061 default:
1062 fprintf(output, "UNKNOWN %d\n", op->op); return;
1063 }
1064 fprintf(output, "\n");
1065finish:
1066 if (op->ch1 >= 0)
1067 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1068 if (op->ch2 >= 0)
1069 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1070}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001071
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001072/**
1073 * xmlXPathDebugDumpCompExpr:
1074 * @output: the FILE * for the output
1075 * @comp: the precompiled XPath expression
1076 * @depth: the indentation level.
1077 *
1078 * Dumps the tree of the compiled XPath expression.
1079 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001080void
1081xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1082 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001083 int i;
1084 char shift[100];
1085
Daniel Veillarda82b1822004-11-08 16:24:57 +00001086 if ((output == NULL) || (comp == NULL)) return;
1087
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001088 for (i = 0;((i < depth) && (i < 25));i++)
1089 shift[2 * i] = shift[2 * i + 1] = ' ';
1090 shift[2 * i] = shift[2 * i + 1] = 0;
1091
1092 fprintf(output, shift);
1093
1094 if (comp == NULL) {
1095 fprintf(output, "Compiled Expression is NULL\n");
1096 return;
1097 }
1098 fprintf(output, "Compiled Expression : %d elements\n",
1099 comp->nbStep);
1100 i = comp->last;
1101 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1102}
Daniel Veillard017b1082001-06-21 11:20:21 +00001103#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001104
1105/************************************************************************
1106 * *
1107 * Parser stacks related functions and macros *
1108 * *
1109 ************************************************************************/
1110
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001111/**
1112 * valuePop:
1113 * @ctxt: an XPath evaluation context
1114 *
1115 * Pops the top XPath object from the value stack
1116 *
1117 * Returns the XPath object just removed
1118 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001119extern xmlXPathObjectPtr
1120valuePop(xmlXPathParserContextPtr ctxt)
1121{
1122 xmlXPathObjectPtr ret;
1123
Daniel Veillarda82b1822004-11-08 16:24:57 +00001124 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard1c732d22002-11-30 11:22:59 +00001125 return (0);
1126 ctxt->valueNr--;
1127 if (ctxt->valueNr > 0)
1128 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1129 else
1130 ctxt->value = NULL;
1131 ret = ctxt->valueTab[ctxt->valueNr];
1132 ctxt->valueTab[ctxt->valueNr] = 0;
1133 return (ret);
1134}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001135/**
1136 * valuePush:
1137 * @ctxt: an XPath evaluation context
1138 * @value: the XPath object
1139 *
1140 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001141 *
1142 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001143 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001144extern int
1145valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1146{
Daniel Veillarda82b1822004-11-08 16:24:57 +00001147 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00001148 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001149 xmlXPathObjectPtr *tmp;
1150
1151 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1152 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00001153 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001154 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00001155 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1156 return (0);
1157 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001158 ctxt->valueMax *= 2;
1159 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00001160 }
1161 ctxt->valueTab[ctxt->valueNr] = value;
1162 ctxt->value = value;
1163 return (ctxt->valueNr++);
1164}
Owen Taylor3473f882001-02-23 17:55:21 +00001165
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001166/**
1167 * xmlXPathPopBoolean:
1168 * @ctxt: an XPath parser context
1169 *
1170 * Pops a boolean from the stack, handling conversion if needed.
1171 * Check error with #xmlXPathCheckError.
1172 *
1173 * Returns the boolean
1174 */
1175int
1176xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1177 xmlXPathObjectPtr obj;
1178 int ret;
1179
1180 obj = valuePop(ctxt);
1181 if (obj == NULL) {
1182 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1183 return(0);
1184 }
William M. Brack08171912003-12-29 02:52:11 +00001185 if (obj->type != XPATH_BOOLEAN)
1186 ret = xmlXPathCastToBoolean(obj);
1187 else
1188 ret = obj->boolval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001189 xmlXPathFreeObject(obj);
1190 return(ret);
1191}
1192
1193/**
1194 * xmlXPathPopNumber:
1195 * @ctxt: an XPath parser context
1196 *
1197 * Pops a number from the stack, handling conversion if needed.
1198 * Check error with #xmlXPathCheckError.
1199 *
1200 * Returns the number
1201 */
1202double
1203xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1204 xmlXPathObjectPtr obj;
1205 double ret;
1206
1207 obj = valuePop(ctxt);
1208 if (obj == NULL) {
1209 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1210 return(0);
1211 }
William M. Brack08171912003-12-29 02:52:11 +00001212 if (obj->type != XPATH_NUMBER)
1213 ret = xmlXPathCastToNumber(obj);
1214 else
1215 ret = obj->floatval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001216 xmlXPathFreeObject(obj);
1217 return(ret);
1218}
1219
1220/**
1221 * xmlXPathPopString:
1222 * @ctxt: an XPath parser context
1223 *
1224 * Pops a string from the stack, handling conversion if needed.
1225 * Check error with #xmlXPathCheckError.
1226 *
1227 * Returns the string
1228 */
1229xmlChar *
1230xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1231 xmlXPathObjectPtr obj;
1232 xmlChar * ret;
1233
1234 obj = valuePop(ctxt);
1235 if (obj == NULL) {
1236 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1237 return(NULL);
1238 }
William M. Brack08171912003-12-29 02:52:11 +00001239 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001240 /* TODO: needs refactoring somewhere else */
1241 if (obj->stringval == ret)
1242 obj->stringval = NULL;
1243 xmlXPathFreeObject(obj);
1244 return(ret);
1245}
1246
1247/**
1248 * xmlXPathPopNodeSet:
1249 * @ctxt: an XPath parser context
1250 *
1251 * Pops a node-set from the stack, handling conversion if needed.
1252 * Check error with #xmlXPathCheckError.
1253 *
1254 * Returns the node-set
1255 */
1256xmlNodeSetPtr
1257xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1258 xmlXPathObjectPtr obj;
1259 xmlNodeSetPtr ret;
1260
Daniel Veillardf2a36f92004-11-08 17:55:01 +00001261 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001262 if (ctxt->value == NULL) {
1263 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1264 return(NULL);
1265 }
1266 if (!xmlXPathStackIsNodeSet(ctxt)) {
1267 xmlXPathSetTypeError(ctxt);
1268 return(NULL);
1269 }
1270 obj = valuePop(ctxt);
1271 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00001272#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00001273 /* to fix memory leak of not clearing obj->user */
1274 if (obj->boolval && obj->user != NULL)
1275 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00001276#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001277 xmlXPathFreeNodeSetList(obj);
1278 return(ret);
1279}
1280
1281/**
1282 * xmlXPathPopExternal:
1283 * @ctxt: an XPath parser context
1284 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001285 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001286 * Check error with #xmlXPathCheckError.
1287 *
1288 * Returns the object
1289 */
1290void *
1291xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1292 xmlXPathObjectPtr obj;
1293 void * ret;
1294
Daniel Veillarda82b1822004-11-08 16:24:57 +00001295 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001296 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1297 return(NULL);
1298 }
1299 if (ctxt->value->type != XPATH_USERS) {
1300 xmlXPathSetTypeError(ctxt);
1301 return(NULL);
1302 }
1303 obj = valuePop(ctxt);
1304 ret = obj->user;
1305 xmlXPathFreeObject(obj);
1306 return(ret);
1307}
1308
Owen Taylor3473f882001-02-23 17:55:21 +00001309/*
1310 * Macros for accessing the content. Those should be used only by the parser,
1311 * and not exported.
1312 *
1313 * Dirty macros, i.e. one need to make assumption on the context to use them
1314 *
1315 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1316 * CUR returns the current xmlChar value, i.e. a 8 bit value
1317 * in ISO-Latin or UTF-8.
1318 * This should be used internally by the parser
1319 * only to compare to ASCII values otherwise it would break when
1320 * running with UTF-8 encoding.
1321 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1322 * to compare on ASCII based substring.
1323 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1324 * strings within the parser.
1325 * CURRENT Returns the current char value, with the full decoding of
1326 * UTF-8 if we are using this mode. It returns an int.
1327 * NEXT Skip to the next character, this does the proper decoding
1328 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1329 * It returns the pointer to the current xmlChar.
1330 */
1331
1332#define CUR (*ctxt->cur)
1333#define SKIP(val) ctxt->cur += (val)
1334#define NXT(val) ctxt->cur[(val)]
1335#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001336#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1337
1338#define COPY_BUF(l,b,i,v) \
1339 if (l == 1) b[i++] = (xmlChar) v; \
1340 else i += xmlCopyChar(l,&b[i],v)
1341
1342#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001343
1344#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001345 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001346
1347#define CURRENT (*ctxt->cur)
1348#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1349
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001350
1351#ifndef DBL_DIG
1352#define DBL_DIG 16
1353#endif
1354#ifndef DBL_EPSILON
1355#define DBL_EPSILON 1E-9
1356#endif
1357
1358#define UPPER_DOUBLE 1E9
1359#define LOWER_DOUBLE 1E-5
1360
1361#define INTEGER_DIGITS DBL_DIG
1362#define FRACTION_DIGITS (DBL_DIG + 1)
1363#define EXPONENT_DIGITS (3 + 2)
1364
1365/**
1366 * xmlXPathFormatNumber:
1367 * @number: number to format
1368 * @buffer: output buffer
1369 * @buffersize: size of output buffer
1370 *
1371 * Convert the number into a string representation.
1372 */
1373static void
1374xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1375{
Daniel Veillardcda96922001-08-21 10:56:31 +00001376 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001377 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001378 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001379 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001380 break;
1381 case -1:
1382 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001383 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001384 break;
1385 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001386 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001387 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001388 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001389 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001390 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001391 } else if (number == ((int) number)) {
1392 char work[30];
1393 char *ptr, *cur;
1394 int res, value = (int) number;
1395
1396 ptr = &buffer[0];
1397 if (value < 0) {
1398 *ptr++ = '-';
1399 value = -value;
1400 }
1401 if (value == 0) {
1402 *ptr++ = '0';
1403 } else {
1404 cur = &work[0];
1405 while (value != 0) {
1406 res = value % 10;
1407 value = value / 10;
1408 *cur++ = '0' + res;
1409 }
1410 cur--;
1411 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1412 *ptr++ = *cur--;
1413 }
1414 }
1415 if (ptr - buffer < buffersize) {
1416 *ptr = 0;
1417 } else if (buffersize > 0) {
1418 ptr--;
1419 *ptr = 0;
1420 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001421 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001422 /* 3 is sign, decimal point, and terminating zero */
1423 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1424 int integer_place, fraction_place;
1425 char *ptr;
1426 char *after_fraction;
1427 double absolute_value;
1428 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001429
Bjorn Reese70a9da52001-04-21 16:57:29 +00001430 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001431
Bjorn Reese70a9da52001-04-21 16:57:29 +00001432 /*
1433 * First choose format - scientific or regular floating point.
1434 * In either case, result is in work, and after_fraction points
1435 * just past the fractional part.
1436 */
1437 if ( ((absolute_value > UPPER_DOUBLE) ||
1438 (absolute_value < LOWER_DOUBLE)) &&
1439 (absolute_value != 0.0) ) {
1440 /* Use scientific notation */
1441 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1442 fraction_place = DBL_DIG - 1;
1443 snprintf(work, sizeof(work),"%*.*e",
1444 integer_place, fraction_place, number);
1445 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001446 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001447 else {
1448 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001449 if (absolute_value > 0.0)
1450 integer_place = 1 + (int)log10(absolute_value);
1451 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001452 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001453 fraction_place = (integer_place > 0)
1454 ? DBL_DIG - integer_place
1455 : DBL_DIG;
1456 size = snprintf(work, sizeof(work), "%0.*f",
1457 fraction_place, number);
1458 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001459 }
1460
Bjorn Reese70a9da52001-04-21 16:57:29 +00001461 /* Remove fractional trailing zeroes */
1462 ptr = after_fraction;
1463 while (*(--ptr) == '0')
1464 ;
1465 if (*ptr != '.')
1466 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001467 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001468
1469 /* Finally copy result back to caller */
1470 size = strlen(work) + 1;
1471 if (size > buffersize) {
1472 work[buffersize - 1] = 0;
1473 size = buffersize;
1474 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001475 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001476 }
1477 break;
1478 }
1479}
1480
Owen Taylor3473f882001-02-23 17:55:21 +00001481
1482/************************************************************************
1483 * *
1484 * Routines to handle NodeSets *
1485 * *
1486 ************************************************************************/
1487
1488/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001489 * xmlXPathOrderDocElems:
1490 * @doc: an input document
1491 *
1492 * Call this routine to speed up XPath computation on static documents.
1493 * This stamps all the element nodes with the document order
1494 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00001495 * field, the value stored is actually - the node number (starting at -1)
1496 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001497 *
William M. Brack08171912003-12-29 02:52:11 +00001498 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001499 * of error.
1500 */
1501long
1502xmlXPathOrderDocElems(xmlDocPtr doc) {
1503 long count = 0;
1504 xmlNodePtr cur;
1505
1506 if (doc == NULL)
1507 return(-1);
1508 cur = doc->children;
1509 while (cur != NULL) {
1510 if (cur->type == XML_ELEMENT_NODE) {
1511 cur->content = (void *) (-(++count));
1512 if (cur->children != NULL) {
1513 cur = cur->children;
1514 continue;
1515 }
1516 }
1517 if (cur->next != NULL) {
1518 cur = cur->next;
1519 continue;
1520 }
1521 do {
1522 cur = cur->parent;
1523 if (cur == NULL)
1524 break;
1525 if (cur == (xmlNodePtr) doc) {
1526 cur = NULL;
1527 break;
1528 }
1529 if (cur->next != NULL) {
1530 cur = cur->next;
1531 break;
1532 }
1533 } while (cur != NULL);
1534 }
1535 return(count);
1536}
1537
1538/**
Owen Taylor3473f882001-02-23 17:55:21 +00001539 * xmlXPathCmpNodes:
1540 * @node1: the first node
1541 * @node2: the second node
1542 *
1543 * Compare two nodes w.r.t document order
1544 *
1545 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00001546 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001547 */
1548int
1549xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1550 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001551 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001552 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001553 xmlNodePtr cur, root;
1554
1555 if ((node1 == NULL) || (node2 == NULL))
1556 return(-2);
1557 /*
1558 * a couple of optimizations which will avoid computations in most cases
1559 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001560 if (node1->type == XML_ATTRIBUTE_NODE) {
1561 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001562 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001563 node1 = node1->parent;
1564 }
1565 if (node2->type == XML_ATTRIBUTE_NODE) {
1566 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001567 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001568 node2 = node2->parent;
1569 }
1570 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001571 if (attr1 == attr2) {
1572 /* not required, but we keep attributes in order */
1573 if (attr1 != 0) {
1574 cur = attrNode2->prev;
1575 while (cur != NULL) {
1576 if (cur == attrNode1)
1577 return (1);
1578 cur = cur->prev;
1579 }
1580 return (-1);
1581 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001582 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001583 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001584 if (attr2 == 1)
1585 return(1);
1586 return(-1);
1587 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001588 if ((node1->type == XML_NAMESPACE_DECL) ||
1589 (node2->type == XML_NAMESPACE_DECL))
1590 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001591 if (node1 == node2->prev)
1592 return(1);
1593 if (node1 == node2->next)
1594 return(-1);
1595
1596 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001597 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001598 */
1599 if ((node1->type == XML_ELEMENT_NODE) &&
1600 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001601 (0 > (long) node1->content) &&
1602 (0 > (long) node2->content) &&
1603 (node1->doc == node2->doc)) {
1604 long l1, l2;
1605
1606 l1 = -((long) node1->content);
1607 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001608 if (l1 < l2)
1609 return(1);
1610 if (l1 > l2)
1611 return(-1);
1612 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001613
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001614 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001615 * compute depth to root
1616 */
1617 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1618 if (cur == node1)
1619 return(1);
1620 depth2++;
1621 }
1622 root = cur;
1623 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1624 if (cur == node2)
1625 return(-1);
1626 depth1++;
1627 }
1628 /*
1629 * Distinct document (or distinct entities :-( ) case.
1630 */
1631 if (root != cur) {
1632 return(-2);
1633 }
1634 /*
1635 * get the nearest common ancestor.
1636 */
1637 while (depth1 > depth2) {
1638 depth1--;
1639 node1 = node1->parent;
1640 }
1641 while (depth2 > depth1) {
1642 depth2--;
1643 node2 = node2->parent;
1644 }
1645 while (node1->parent != node2->parent) {
1646 node1 = node1->parent;
1647 node2 = node2->parent;
1648 /* should not happen but just in case ... */
1649 if ((node1 == NULL) || (node2 == NULL))
1650 return(-2);
1651 }
1652 /*
1653 * Find who's first.
1654 */
Daniel Veillardf49be472004-02-17 11:48:18 +00001655 if (node1 == node2->prev)
1656 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001657 if (node1 == node2->next)
1658 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00001659 /*
1660 * Speedup using document order if availble.
1661 */
1662 if ((node1->type == XML_ELEMENT_NODE) &&
1663 (node2->type == XML_ELEMENT_NODE) &&
1664 (0 > (long) node1->content) &&
1665 (0 > (long) node2->content) &&
1666 (node1->doc == node2->doc)) {
1667 long l1, l2;
1668
1669 l1 = -((long) node1->content);
1670 l2 = -((long) node2->content);
1671 if (l1 < l2)
1672 return(1);
1673 if (l1 > l2)
1674 return(-1);
1675 }
1676
Owen Taylor3473f882001-02-23 17:55:21 +00001677 for (cur = node1->next;cur != NULL;cur = cur->next)
1678 if (cur == node2)
1679 return(1);
1680 return(-1); /* assume there is no sibling list corruption */
1681}
1682
1683/**
1684 * xmlXPathNodeSetSort:
1685 * @set: the node set
1686 *
1687 * Sort the node set in document order
1688 */
1689void
1690xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001691 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001692 xmlNodePtr tmp;
1693
1694 if (set == NULL)
1695 return;
1696
1697 /* Use Shell's sort to sort the node-set */
1698 len = set->nodeNr;
1699 for (incr = len / 2; incr > 0; incr /= 2) {
1700 for (i = incr; i < len; i++) {
1701 j = i - incr;
1702 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001703 if (xmlXPathCmpNodes(set->nodeTab[j],
1704 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001705 tmp = set->nodeTab[j];
1706 set->nodeTab[j] = set->nodeTab[j + incr];
1707 set->nodeTab[j + incr] = tmp;
1708 j -= incr;
1709 } else
1710 break;
1711 }
1712 }
1713 }
1714}
1715
1716#define XML_NODESET_DEFAULT 10
1717/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001718 * xmlXPathNodeSetDupNs:
1719 * @node: the parent node of the namespace XPath node
1720 * @ns: the libxml namespace declaration node.
1721 *
1722 * Namespace node in libxml don't match the XPath semantic. In a node set
1723 * the namespace nodes are duplicated and the next pointer is set to the
1724 * parent node in the XPath semantic.
1725 *
1726 * Returns the newly created object.
1727 */
1728static xmlNodePtr
1729xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1730 xmlNsPtr cur;
1731
1732 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1733 return(NULL);
1734 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1735 return((xmlNodePtr) ns);
1736
1737 /*
1738 * Allocate a new Namespace and fill the fields.
1739 */
1740 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1741 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001742 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001743 return(NULL);
1744 }
1745 memset(cur, 0, sizeof(xmlNs));
1746 cur->type = XML_NAMESPACE_DECL;
1747 if (ns->href != NULL)
1748 cur->href = xmlStrdup(ns->href);
1749 if (ns->prefix != NULL)
1750 cur->prefix = xmlStrdup(ns->prefix);
1751 cur->next = (xmlNsPtr) node;
1752 return((xmlNodePtr) cur);
1753}
1754
1755/**
1756 * xmlXPathNodeSetFreeNs:
1757 * @ns: the XPath namespace node found in a nodeset.
1758 *
William M. Brack08171912003-12-29 02:52:11 +00001759 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001760 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00001761 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001762 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001763void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001764xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1765 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1766 return;
1767
1768 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1769 if (ns->href != NULL)
1770 xmlFree((xmlChar *)ns->href);
1771 if (ns->prefix != NULL)
1772 xmlFree((xmlChar *)ns->prefix);
1773 xmlFree(ns);
1774 }
1775}
1776
1777/**
Owen Taylor3473f882001-02-23 17:55:21 +00001778 * xmlXPathNodeSetCreate:
1779 * @val: an initial xmlNodePtr, or NULL
1780 *
1781 * Create a new xmlNodeSetPtr of type double and of value @val
1782 *
1783 * Returns the newly created object.
1784 */
1785xmlNodeSetPtr
1786xmlXPathNodeSetCreate(xmlNodePtr val) {
1787 xmlNodeSetPtr ret;
1788
1789 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1790 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001791 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001792 return(NULL);
1793 }
1794 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1795 if (val != NULL) {
1796 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1797 sizeof(xmlNodePtr));
1798 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001799 xmlXPathErrMemory(NULL, "creating nodeset\n");
1800 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001801 return(NULL);
1802 }
1803 memset(ret->nodeTab, 0 ,
1804 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1805 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001806 if (val->type == XML_NAMESPACE_DECL) {
1807 xmlNsPtr ns = (xmlNsPtr) val;
1808
1809 ret->nodeTab[ret->nodeNr++] =
1810 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1811 } else
1812 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001813 }
1814 return(ret);
1815}
1816
1817/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001818 * xmlXPathNodeSetContains:
1819 * @cur: the node-set
1820 * @val: the node
1821 *
1822 * checks whether @cur contains @val
1823 *
1824 * Returns true (1) if @cur contains @val, false (0) otherwise
1825 */
1826int
1827xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1828 int i;
1829
Daniel Veillarda82b1822004-11-08 16:24:57 +00001830 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001831 if (val->type == XML_NAMESPACE_DECL) {
1832 for (i = 0; i < cur->nodeNr; i++) {
1833 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1834 xmlNsPtr ns1, ns2;
1835
1836 ns1 = (xmlNsPtr) val;
1837 ns2 = (xmlNsPtr) cur->nodeTab[i];
1838 if (ns1 == ns2)
1839 return(1);
1840 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1841 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1842 return(1);
1843 }
1844 }
1845 } else {
1846 for (i = 0; i < cur->nodeNr; i++) {
1847 if (cur->nodeTab[i] == val)
1848 return(1);
1849 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001850 }
1851 return(0);
1852}
1853
1854/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001855 * xmlXPathNodeSetAddNs:
1856 * @cur: the initial node set
1857 * @node: the hosting node
1858 * @ns: a the namespace node
1859 *
1860 * add a new namespace node to an existing NodeSet
1861 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001862void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001863xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1864 int i;
1865
Daniel Veillarda82b1822004-11-08 16:24:57 +00001866
1867 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
1868 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001869 (node->type != XML_ELEMENT_NODE))
1870 return;
1871
William M. Brack08171912003-12-29 02:52:11 +00001872 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001873 /*
William M. Brack08171912003-12-29 02:52:11 +00001874 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001875 */
1876 for (i = 0;i < cur->nodeNr;i++) {
1877 if ((cur->nodeTab[i] != NULL) &&
1878 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001879 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001880 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1881 return;
1882 }
1883
1884 /*
1885 * grow the nodeTab if needed
1886 */
1887 if (cur->nodeMax == 0) {
1888 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1889 sizeof(xmlNodePtr));
1890 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001891 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001892 return;
1893 }
1894 memset(cur->nodeTab, 0 ,
1895 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1896 cur->nodeMax = XML_NODESET_DEFAULT;
1897 } else if (cur->nodeNr == cur->nodeMax) {
1898 xmlNodePtr *temp;
1899
1900 cur->nodeMax *= 2;
1901 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1902 sizeof(xmlNodePtr));
1903 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001904 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001905 return;
1906 }
1907 cur->nodeTab = temp;
1908 }
1909 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1910}
1911
1912/**
Owen Taylor3473f882001-02-23 17:55:21 +00001913 * xmlXPathNodeSetAdd:
1914 * @cur: the initial node set
1915 * @val: a new xmlNodePtr
1916 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001917 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001918 */
1919void
1920xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1921 int i;
1922
Daniel Veillarda82b1822004-11-08 16:24:57 +00001923 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001924
Daniel Veillardef0b4502003-03-24 13:57:34 +00001925#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001926 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1927 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001928#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001929
William M. Brack08171912003-12-29 02:52:11 +00001930 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001931 /*
William M. Brack08171912003-12-29 02:52:11 +00001932 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00001933 */
1934 for (i = 0;i < cur->nodeNr;i++)
1935 if (cur->nodeTab[i] == val) return;
1936
1937 /*
1938 * grow the nodeTab if needed
1939 */
1940 if (cur->nodeMax == 0) {
1941 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1942 sizeof(xmlNodePtr));
1943 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001944 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001945 return;
1946 }
1947 memset(cur->nodeTab, 0 ,
1948 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1949 cur->nodeMax = XML_NODESET_DEFAULT;
1950 } else if (cur->nodeNr == cur->nodeMax) {
1951 xmlNodePtr *temp;
1952
1953 cur->nodeMax *= 2;
1954 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1955 sizeof(xmlNodePtr));
1956 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001957 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001958 return;
1959 }
1960 cur->nodeTab = temp;
1961 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001962 if (val->type == XML_NAMESPACE_DECL) {
1963 xmlNsPtr ns = (xmlNsPtr) val;
1964
1965 cur->nodeTab[cur->nodeNr++] =
1966 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1967 } else
1968 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001969}
1970
1971/**
1972 * xmlXPathNodeSetAddUnique:
1973 * @cur: the initial node set
1974 * @val: a new xmlNodePtr
1975 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001976 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001977 * when we are sure the node is not already in the set.
1978 */
1979void
1980xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00001981 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001982
Daniel Veillardef0b4502003-03-24 13:57:34 +00001983#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001984 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1985 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001986#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001987
William M. Brack08171912003-12-29 02:52:11 +00001988 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001989 /*
1990 * grow the nodeTab if needed
1991 */
1992 if (cur->nodeMax == 0) {
1993 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1994 sizeof(xmlNodePtr));
1995 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001996 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001997 return;
1998 }
1999 memset(cur->nodeTab, 0 ,
2000 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2001 cur->nodeMax = XML_NODESET_DEFAULT;
2002 } else if (cur->nodeNr == cur->nodeMax) {
2003 xmlNodePtr *temp;
2004
2005 cur->nodeMax *= 2;
2006 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
2007 sizeof(xmlNodePtr));
2008 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002009 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002010 return;
2011 }
2012 cur->nodeTab = temp;
2013 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002014 if (val->type == XML_NAMESPACE_DECL) {
2015 xmlNsPtr ns = (xmlNsPtr) val;
2016
2017 cur->nodeTab[cur->nodeNr++] =
2018 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2019 } else
2020 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00002021}
2022
2023/**
2024 * xmlXPathNodeSetMerge:
2025 * @val1: the first NodeSet or NULL
2026 * @val2: the second NodeSet
2027 *
2028 * Merges two nodesets, all nodes from @val2 are added to @val1
2029 * if @val1 is NULL, a new set is created and copied from @val2
2030 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002031 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002032 */
2033xmlNodeSetPtr
2034xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002035 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00002036
2037 if (val2 == NULL) return(val1);
2038 if (val1 == NULL) {
2039 val1 = xmlXPathNodeSetCreate(NULL);
2040 }
2041
William M. Brack08171912003-12-29 02:52:11 +00002042 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002043 initNr = val1->nodeNr;
2044
2045 for (i = 0;i < val2->nodeNr;i++) {
2046 /*
William M. Brack08171912003-12-29 02:52:11 +00002047 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00002048 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002049 skip = 0;
2050 for (j = 0; j < initNr; j++) {
2051 if (val1->nodeTab[j] == val2->nodeTab[i]) {
2052 skip = 1;
2053 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002054 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
2055 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
2056 xmlNsPtr ns1, ns2;
2057 ns1 = (xmlNsPtr) val1->nodeTab[j];
2058 ns2 = (xmlNsPtr) val2->nodeTab[i];
2059 if ((ns1->next == ns2->next) &&
2060 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
2061 skip = 1;
2062 break;
2063 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002064 }
2065 }
2066 if (skip)
2067 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00002068
2069 /*
2070 * grow the nodeTab if needed
2071 */
2072 if (val1->nodeMax == 0) {
2073 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2074 sizeof(xmlNodePtr));
2075 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002076 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002077 return(NULL);
2078 }
2079 memset(val1->nodeTab, 0 ,
2080 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2081 val1->nodeMax = XML_NODESET_DEFAULT;
2082 } else if (val1->nodeNr == val1->nodeMax) {
2083 xmlNodePtr *temp;
2084
2085 val1->nodeMax *= 2;
2086 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2087 sizeof(xmlNodePtr));
2088 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002089 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002090 return(NULL);
2091 }
2092 val1->nodeTab = temp;
2093 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002094 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2095 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2096
2097 val1->nodeTab[val1->nodeNr++] =
2098 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2099 } else
2100 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002101 }
2102
2103 return(val1);
2104}
2105
2106/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002107 * xmlXPathNodeSetMergeUnique:
2108 * @val1: the first NodeSet or NULL
2109 * @val2: the second NodeSet
2110 *
2111 * Merges two nodesets, all nodes from @val2 are added to @val1
2112 * if @val1 is NULL, a new set is created and copied from @val2
2113 *
2114 * Returns @val1 once extended or NULL in case of error.
2115 */
2116static xmlNodeSetPtr
2117xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002118 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002119
2120 if (val2 == NULL) return(val1);
2121 if (val1 == NULL) {
2122 val1 = xmlXPathNodeSetCreate(NULL);
2123 }
2124
William M. Brack08171912003-12-29 02:52:11 +00002125 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002126
2127 for (i = 0;i < val2->nodeNr;i++) {
2128 /*
2129 * grow the nodeTab if needed
2130 */
2131 if (val1->nodeMax == 0) {
2132 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2133 sizeof(xmlNodePtr));
2134 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002135 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002136 return(NULL);
2137 }
2138 memset(val1->nodeTab, 0 ,
2139 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2140 val1->nodeMax = XML_NODESET_DEFAULT;
2141 } else if (val1->nodeNr == val1->nodeMax) {
2142 xmlNodePtr *temp;
2143
2144 val1->nodeMax *= 2;
2145 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2146 sizeof(xmlNodePtr));
2147 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002148 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002149 return(NULL);
2150 }
2151 val1->nodeTab = temp;
2152 }
2153 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2154 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2155
2156 val1->nodeTab[val1->nodeNr++] =
2157 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2158 } else
2159 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2160 }
2161
2162 return(val1);
2163}
2164
2165/**
Owen Taylor3473f882001-02-23 17:55:21 +00002166 * xmlXPathNodeSetDel:
2167 * @cur: the initial node set
2168 * @val: an xmlNodePtr
2169 *
2170 * Removes an xmlNodePtr from an existing NodeSet
2171 */
2172void
2173xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2174 int i;
2175
2176 if (cur == NULL) return;
2177 if (val == NULL) return;
2178
2179 /*
William M. Brack08171912003-12-29 02:52:11 +00002180 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002181 */
2182 for (i = 0;i < cur->nodeNr;i++)
2183 if (cur->nodeTab[i] == val) break;
2184
William M. Brack08171912003-12-29 02:52:11 +00002185 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002186#ifdef DEBUG
2187 xmlGenericError(xmlGenericErrorContext,
2188 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2189 val->name);
2190#endif
2191 return;
2192 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002193 if ((cur->nodeTab[i] != NULL) &&
2194 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2195 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002196 cur->nodeNr--;
2197 for (;i < cur->nodeNr;i++)
2198 cur->nodeTab[i] = cur->nodeTab[i + 1];
2199 cur->nodeTab[cur->nodeNr] = NULL;
2200}
2201
2202/**
2203 * xmlXPathNodeSetRemove:
2204 * @cur: the initial node set
2205 * @val: the index to remove
2206 *
2207 * Removes an entry from an existing NodeSet list.
2208 */
2209void
2210xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2211 if (cur == NULL) return;
2212 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002213 if ((cur->nodeTab[val] != NULL) &&
2214 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2215 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002216 cur->nodeNr--;
2217 for (;val < cur->nodeNr;val++)
2218 cur->nodeTab[val] = cur->nodeTab[val + 1];
2219 cur->nodeTab[cur->nodeNr] = NULL;
2220}
2221
2222/**
2223 * xmlXPathFreeNodeSet:
2224 * @obj: the xmlNodeSetPtr to free
2225 *
2226 * Free the NodeSet compound (not the actual nodes !).
2227 */
2228void
2229xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2230 if (obj == NULL) return;
2231 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002232 int i;
2233
William M. Brack08171912003-12-29 02:52:11 +00002234 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002235 for (i = 0;i < obj->nodeNr;i++)
2236 if ((obj->nodeTab[i] != NULL) &&
2237 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2238 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002239 xmlFree(obj->nodeTab);
2240 }
Owen Taylor3473f882001-02-23 17:55:21 +00002241 xmlFree(obj);
2242}
2243
2244/**
2245 * xmlXPathFreeValueTree:
2246 * @obj: the xmlNodeSetPtr to free
2247 *
2248 * Free the NodeSet compound and the actual tree, this is different
2249 * from xmlXPathFreeNodeSet()
2250 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002251static void
Owen Taylor3473f882001-02-23 17:55:21 +00002252xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2253 int i;
2254
2255 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002256
2257 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002258 for (i = 0;i < obj->nodeNr;i++) {
2259 if (obj->nodeTab[i] != NULL) {
2260 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2261 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2262 } else {
2263 xmlFreeNodeList(obj->nodeTab[i]);
2264 }
2265 }
2266 }
Owen Taylor3473f882001-02-23 17:55:21 +00002267 xmlFree(obj->nodeTab);
2268 }
Owen Taylor3473f882001-02-23 17:55:21 +00002269 xmlFree(obj);
2270}
2271
2272#if defined(DEBUG) || defined(DEBUG_STEP)
2273/**
2274 * xmlGenericErrorContextNodeSet:
2275 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002276 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002277 *
2278 * Quick display of a NodeSet
2279 */
2280void
2281xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2282 int i;
2283
2284 if (output == NULL) output = xmlGenericErrorContext;
2285 if (obj == NULL) {
2286 fprintf(output, "NodeSet == NULL !\n");
2287 return;
2288 }
2289 if (obj->nodeNr == 0) {
2290 fprintf(output, "NodeSet is empty\n");
2291 return;
2292 }
2293 if (obj->nodeTab == NULL) {
2294 fprintf(output, " nodeTab == NULL !\n");
2295 return;
2296 }
2297 for (i = 0; i < obj->nodeNr; i++) {
2298 if (obj->nodeTab[i] == NULL) {
2299 fprintf(output, " NULL !\n");
2300 return;
2301 }
2302 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2303 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2304 fprintf(output, " /");
2305 else if (obj->nodeTab[i]->name == NULL)
2306 fprintf(output, " noname!");
2307 else fprintf(output, " %s", obj->nodeTab[i]->name);
2308 }
2309 fprintf(output, "\n");
2310}
2311#endif
2312
2313/**
2314 * xmlXPathNewNodeSet:
2315 * @val: the NodePtr value
2316 *
2317 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2318 * it with the single Node @val
2319 *
2320 * Returns the newly created object.
2321 */
2322xmlXPathObjectPtr
2323xmlXPathNewNodeSet(xmlNodePtr val) {
2324 xmlXPathObjectPtr ret;
2325
2326 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2327 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002328 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002329 return(NULL);
2330 }
2331 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2332 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002333 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002334 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002335 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002336 return(ret);
2337}
2338
2339/**
2340 * xmlXPathNewValueTree:
2341 * @val: the NodePtr value
2342 *
2343 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2344 * it with the tree root @val
2345 *
2346 * Returns the newly created object.
2347 */
2348xmlXPathObjectPtr
2349xmlXPathNewValueTree(xmlNodePtr val) {
2350 xmlXPathObjectPtr ret;
2351
2352 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2353 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002354 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002355 return(NULL);
2356 }
2357 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2358 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002359 ret->boolval = 1;
2360 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002361 ret->nodesetval = xmlXPathNodeSetCreate(val);
2362 return(ret);
2363}
2364
2365/**
2366 * xmlXPathNewNodeSetList:
2367 * @val: an existing NodeSet
2368 *
2369 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2370 * it with the Nodeset @val
2371 *
2372 * Returns the newly created object.
2373 */
2374xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002375xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2376{
Owen Taylor3473f882001-02-23 17:55:21 +00002377 xmlXPathObjectPtr ret;
2378 int i;
2379
2380 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002381 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002382 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002383 ret = xmlXPathNewNodeSet(NULL);
2384 else {
2385 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2386 for (i = 1; i < val->nodeNr; ++i)
2387 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2388 }
Owen Taylor3473f882001-02-23 17:55:21 +00002389
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002390 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002391}
2392
2393/**
2394 * xmlXPathWrapNodeSet:
2395 * @val: the NodePtr value
2396 *
2397 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2398 *
2399 * Returns the newly created object.
2400 */
2401xmlXPathObjectPtr
2402xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2403 xmlXPathObjectPtr ret;
2404
2405 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2406 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002407 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002408 return(NULL);
2409 }
2410 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2411 ret->type = XPATH_NODESET;
2412 ret->nodesetval = val;
2413 return(ret);
2414}
2415
2416/**
2417 * xmlXPathFreeNodeSetList:
2418 * @obj: an existing NodeSetList object
2419 *
2420 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2421 * the list contrary to xmlXPathFreeObject().
2422 */
2423void
2424xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2425 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002426 xmlFree(obj);
2427}
2428
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002429/**
2430 * xmlXPathDifference:
2431 * @nodes1: a node-set
2432 * @nodes2: a node-set
2433 *
2434 * Implements the EXSLT - Sets difference() function:
2435 * node-set set:difference (node-set, node-set)
2436 *
2437 * Returns the difference between the two node sets, or nodes1 if
2438 * nodes2 is empty
2439 */
2440xmlNodeSetPtr
2441xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2442 xmlNodeSetPtr ret;
2443 int i, l1;
2444 xmlNodePtr cur;
2445
2446 if (xmlXPathNodeSetIsEmpty(nodes2))
2447 return(nodes1);
2448
2449 ret = xmlXPathNodeSetCreate(NULL);
2450 if (xmlXPathNodeSetIsEmpty(nodes1))
2451 return(ret);
2452
2453 l1 = xmlXPathNodeSetGetLength(nodes1);
2454
2455 for (i = 0; i < l1; i++) {
2456 cur = xmlXPathNodeSetItem(nodes1, i);
2457 if (!xmlXPathNodeSetContains(nodes2, cur))
2458 xmlXPathNodeSetAddUnique(ret, cur);
2459 }
2460 return(ret);
2461}
2462
2463/**
2464 * xmlXPathIntersection:
2465 * @nodes1: a node-set
2466 * @nodes2: a node-set
2467 *
2468 * Implements the EXSLT - Sets intersection() function:
2469 * node-set set:intersection (node-set, node-set)
2470 *
2471 * Returns a node set comprising the nodes that are within both the
2472 * node sets passed as arguments
2473 */
2474xmlNodeSetPtr
2475xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2476 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2477 int i, l1;
2478 xmlNodePtr cur;
2479
2480 if (xmlXPathNodeSetIsEmpty(nodes1))
2481 return(ret);
2482 if (xmlXPathNodeSetIsEmpty(nodes2))
2483 return(ret);
2484
2485 l1 = xmlXPathNodeSetGetLength(nodes1);
2486
2487 for (i = 0; i < l1; i++) {
2488 cur = xmlXPathNodeSetItem(nodes1, i);
2489 if (xmlXPathNodeSetContains(nodes2, cur))
2490 xmlXPathNodeSetAddUnique(ret, cur);
2491 }
2492 return(ret);
2493}
2494
2495/**
2496 * xmlXPathDistinctSorted:
2497 * @nodes: a node-set, sorted by document order
2498 *
2499 * Implements the EXSLT - Sets distinct() function:
2500 * node-set set:distinct (node-set)
2501 *
2502 * Returns a subset of the nodes contained in @nodes, or @nodes if
2503 * it is empty
2504 */
2505xmlNodeSetPtr
2506xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2507 xmlNodeSetPtr ret;
2508 xmlHashTablePtr hash;
2509 int i, l;
2510 xmlChar * strval;
2511 xmlNodePtr cur;
2512
2513 if (xmlXPathNodeSetIsEmpty(nodes))
2514 return(nodes);
2515
2516 ret = xmlXPathNodeSetCreate(NULL);
2517 l = xmlXPathNodeSetGetLength(nodes);
2518 hash = xmlHashCreate (l);
2519 for (i = 0; i < l; i++) {
2520 cur = xmlXPathNodeSetItem(nodes, i);
2521 strval = xmlXPathCastNodeToString(cur);
2522 if (xmlHashLookup(hash, strval) == NULL) {
2523 xmlHashAddEntry(hash, strval, strval);
2524 xmlXPathNodeSetAddUnique(ret, cur);
2525 } else {
2526 xmlFree(strval);
2527 }
2528 }
2529 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2530 return(ret);
2531}
2532
2533/**
2534 * xmlXPathDistinct:
2535 * @nodes: a node-set
2536 *
2537 * Implements the EXSLT - Sets distinct() function:
2538 * node-set set:distinct (node-set)
2539 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2540 * is called with the sorted node-set
2541 *
2542 * Returns a subset of the nodes contained in @nodes, or @nodes if
2543 * it is empty
2544 */
2545xmlNodeSetPtr
2546xmlXPathDistinct (xmlNodeSetPtr nodes) {
2547 if (xmlXPathNodeSetIsEmpty(nodes))
2548 return(nodes);
2549
2550 xmlXPathNodeSetSort(nodes);
2551 return(xmlXPathDistinctSorted(nodes));
2552}
2553
2554/**
2555 * xmlXPathHasSameNodes:
2556 * @nodes1: a node-set
2557 * @nodes2: a node-set
2558 *
2559 * Implements the EXSLT - Sets has-same-nodes function:
2560 * boolean set:has-same-node(node-set, node-set)
2561 *
2562 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2563 * otherwise
2564 */
2565int
2566xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2567 int i, l;
2568 xmlNodePtr cur;
2569
2570 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2571 xmlXPathNodeSetIsEmpty(nodes2))
2572 return(0);
2573
2574 l = xmlXPathNodeSetGetLength(nodes1);
2575 for (i = 0; i < l; i++) {
2576 cur = xmlXPathNodeSetItem(nodes1, i);
2577 if (xmlXPathNodeSetContains(nodes2, cur))
2578 return(1);
2579 }
2580 return(0);
2581}
2582
2583/**
2584 * xmlXPathNodeLeadingSorted:
2585 * @nodes: a node-set, sorted by document order
2586 * @node: a node
2587 *
2588 * Implements the EXSLT - Sets leading() function:
2589 * node-set set:leading (node-set, node-set)
2590 *
2591 * Returns the nodes in @nodes that precede @node in document order,
2592 * @nodes if @node is NULL or an empty node-set if @nodes
2593 * doesn't contain @node
2594 */
2595xmlNodeSetPtr
2596xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2597 int i, l;
2598 xmlNodePtr cur;
2599 xmlNodeSetPtr ret;
2600
2601 if (node == NULL)
2602 return(nodes);
2603
2604 ret = xmlXPathNodeSetCreate(NULL);
2605 if (xmlXPathNodeSetIsEmpty(nodes) ||
2606 (!xmlXPathNodeSetContains(nodes, node)))
2607 return(ret);
2608
2609 l = xmlXPathNodeSetGetLength(nodes);
2610 for (i = 0; i < l; i++) {
2611 cur = xmlXPathNodeSetItem(nodes, i);
2612 if (cur == node)
2613 break;
2614 xmlXPathNodeSetAddUnique(ret, cur);
2615 }
2616 return(ret);
2617}
2618
2619/**
2620 * xmlXPathNodeLeading:
2621 * @nodes: a node-set
2622 * @node: a node
2623 *
2624 * Implements the EXSLT - Sets leading() function:
2625 * node-set set:leading (node-set, node-set)
2626 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2627 * is called.
2628 *
2629 * Returns the nodes in @nodes that precede @node in document order,
2630 * @nodes if @node is NULL or an empty node-set if @nodes
2631 * doesn't contain @node
2632 */
2633xmlNodeSetPtr
2634xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2635 xmlXPathNodeSetSort(nodes);
2636 return(xmlXPathNodeLeadingSorted(nodes, node));
2637}
2638
2639/**
2640 * xmlXPathLeadingSorted:
2641 * @nodes1: a node-set, sorted by document order
2642 * @nodes2: a node-set, sorted by document order
2643 *
2644 * Implements the EXSLT - Sets leading() function:
2645 * node-set set:leading (node-set, node-set)
2646 *
2647 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2648 * in document order, @nodes1 if @nodes2 is NULL or empty or
2649 * an empty node-set if @nodes1 doesn't contain @nodes2
2650 */
2651xmlNodeSetPtr
2652xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2653 if (xmlXPathNodeSetIsEmpty(nodes2))
2654 return(nodes1);
2655 return(xmlXPathNodeLeadingSorted(nodes1,
2656 xmlXPathNodeSetItem(nodes2, 1)));
2657}
2658
2659/**
2660 * xmlXPathLeading:
2661 * @nodes1: a node-set
2662 * @nodes2: a node-set
2663 *
2664 * Implements the EXSLT - Sets leading() function:
2665 * node-set set:leading (node-set, node-set)
2666 * @nodes1 and @nodes2 are sorted by document order, then
2667 * #exslSetsLeadingSorted is called.
2668 *
2669 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2670 * in document order, @nodes1 if @nodes2 is NULL or empty or
2671 * an empty node-set if @nodes1 doesn't contain @nodes2
2672 */
2673xmlNodeSetPtr
2674xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2675 if (xmlXPathNodeSetIsEmpty(nodes2))
2676 return(nodes1);
2677 if (xmlXPathNodeSetIsEmpty(nodes1))
2678 return(xmlXPathNodeSetCreate(NULL));
2679 xmlXPathNodeSetSort(nodes1);
2680 xmlXPathNodeSetSort(nodes2);
2681 return(xmlXPathNodeLeadingSorted(nodes1,
2682 xmlXPathNodeSetItem(nodes2, 1)));
2683}
2684
2685/**
2686 * xmlXPathNodeTrailingSorted:
2687 * @nodes: a node-set, sorted by document order
2688 * @node: a node
2689 *
2690 * Implements the EXSLT - Sets trailing() function:
2691 * node-set set:trailing (node-set, node-set)
2692 *
2693 * Returns the nodes in @nodes that follow @node in document order,
2694 * @nodes if @node is NULL or an empty node-set if @nodes
2695 * doesn't contain @node
2696 */
2697xmlNodeSetPtr
2698xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2699 int i, l;
2700 xmlNodePtr cur;
2701 xmlNodeSetPtr ret;
2702
2703 if (node == NULL)
2704 return(nodes);
2705
2706 ret = xmlXPathNodeSetCreate(NULL);
2707 if (xmlXPathNodeSetIsEmpty(nodes) ||
2708 (!xmlXPathNodeSetContains(nodes, node)))
2709 return(ret);
2710
2711 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002712 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002713 cur = xmlXPathNodeSetItem(nodes, i);
2714 if (cur == node)
2715 break;
2716 xmlXPathNodeSetAddUnique(ret, cur);
2717 }
2718 return(ret);
2719}
2720
2721/**
2722 * xmlXPathNodeTrailing:
2723 * @nodes: a node-set
2724 * @node: a node
2725 *
2726 * Implements the EXSLT - Sets trailing() function:
2727 * node-set set:trailing (node-set, node-set)
2728 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2729 * is called.
2730 *
2731 * Returns the nodes in @nodes that follow @node in document order,
2732 * @nodes if @node is NULL or an empty node-set if @nodes
2733 * doesn't contain @node
2734 */
2735xmlNodeSetPtr
2736xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2737 xmlXPathNodeSetSort(nodes);
2738 return(xmlXPathNodeTrailingSorted(nodes, node));
2739}
2740
2741/**
2742 * xmlXPathTrailingSorted:
2743 * @nodes1: a node-set, sorted by document order
2744 * @nodes2: a node-set, sorted by document order
2745 *
2746 * Implements the EXSLT - Sets trailing() function:
2747 * node-set set:trailing (node-set, node-set)
2748 *
2749 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2750 * in document order, @nodes1 if @nodes2 is NULL or empty or
2751 * an empty node-set if @nodes1 doesn't contain @nodes2
2752 */
2753xmlNodeSetPtr
2754xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2755 if (xmlXPathNodeSetIsEmpty(nodes2))
2756 return(nodes1);
2757 return(xmlXPathNodeTrailingSorted(nodes1,
2758 xmlXPathNodeSetItem(nodes2, 0)));
2759}
2760
2761/**
2762 * xmlXPathTrailing:
2763 * @nodes1: a node-set
2764 * @nodes2: a node-set
2765 *
2766 * Implements the EXSLT - Sets trailing() function:
2767 * node-set set:trailing (node-set, node-set)
2768 * @nodes1 and @nodes2 are sorted by document order, then
2769 * #xmlXPathTrailingSorted is called.
2770 *
2771 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2772 * in document order, @nodes1 if @nodes2 is NULL or empty or
2773 * an empty node-set if @nodes1 doesn't contain @nodes2
2774 */
2775xmlNodeSetPtr
2776xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2777 if (xmlXPathNodeSetIsEmpty(nodes2))
2778 return(nodes1);
2779 if (xmlXPathNodeSetIsEmpty(nodes1))
2780 return(xmlXPathNodeSetCreate(NULL));
2781 xmlXPathNodeSetSort(nodes1);
2782 xmlXPathNodeSetSort(nodes2);
2783 return(xmlXPathNodeTrailingSorted(nodes1,
2784 xmlXPathNodeSetItem(nodes2, 0)));
2785}
2786
Owen Taylor3473f882001-02-23 17:55:21 +00002787/************************************************************************
2788 * *
2789 * Routines to handle extra functions *
2790 * *
2791 ************************************************************************/
2792
2793/**
2794 * xmlXPathRegisterFunc:
2795 * @ctxt: the XPath context
2796 * @name: the function name
2797 * @f: the function implementation or NULL
2798 *
2799 * Register a new function. If @f is NULL it unregisters the function
2800 *
2801 * Returns 0 in case of success, -1 in case of error
2802 */
2803int
2804xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2805 xmlXPathFunction f) {
2806 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2807}
2808
2809/**
2810 * xmlXPathRegisterFuncNS:
2811 * @ctxt: the XPath context
2812 * @name: the function name
2813 * @ns_uri: the function namespace URI
2814 * @f: the function implementation or NULL
2815 *
2816 * Register a new function. If @f is NULL it unregisters the function
2817 *
2818 * Returns 0 in case of success, -1 in case of error
2819 */
2820int
2821xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2822 const xmlChar *ns_uri, xmlXPathFunction f) {
2823 if (ctxt == NULL)
2824 return(-1);
2825 if (name == NULL)
2826 return(-1);
2827
2828 if (ctxt->funcHash == NULL)
2829 ctxt->funcHash = xmlHashCreate(0);
2830 if (ctxt->funcHash == NULL)
2831 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002832 if (f == NULL)
2833 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00002834 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00002835}
2836
2837/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002838 * xmlXPathRegisterFuncLookup:
2839 * @ctxt: the XPath context
2840 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002841 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002842 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002843 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002844 */
2845void
2846xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2847 xmlXPathFuncLookupFunc f,
2848 void *funcCtxt) {
2849 if (ctxt == NULL)
2850 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002851 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002852 ctxt->funcLookupData = funcCtxt;
2853}
2854
2855/**
Owen Taylor3473f882001-02-23 17:55:21 +00002856 * xmlXPathFunctionLookup:
2857 * @ctxt: the XPath context
2858 * @name: the function name
2859 *
2860 * Search in the Function array of the context for the given
2861 * function.
2862 *
2863 * Returns the xmlXPathFunction or NULL if not found
2864 */
2865xmlXPathFunction
2866xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002867 if (ctxt == NULL)
2868 return (NULL);
2869
2870 if (ctxt->funcLookupFunc != NULL) {
2871 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002872 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002873
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002874 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002875 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002876 if (ret != NULL)
2877 return(ret);
2878 }
Owen Taylor3473f882001-02-23 17:55:21 +00002879 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2880}
2881
2882/**
2883 * xmlXPathFunctionLookupNS:
2884 * @ctxt: the XPath context
2885 * @name: the function name
2886 * @ns_uri: the function namespace URI
2887 *
2888 * Search in the Function array of the context for the given
2889 * function.
2890 *
2891 * Returns the xmlXPathFunction or NULL if not found
2892 */
2893xmlXPathFunction
2894xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2895 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00002896 xmlXPathFunction ret;
2897
Owen Taylor3473f882001-02-23 17:55:21 +00002898 if (ctxt == NULL)
2899 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002900 if (name == NULL)
2901 return(NULL);
2902
Thomas Broyerba4ad322001-07-26 16:55:21 +00002903 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002904 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002905
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002906 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002907 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002908 if (ret != NULL)
2909 return(ret);
2910 }
2911
2912 if (ctxt->funcHash == NULL)
2913 return(NULL);
2914
William M. Brackad0e67c2004-12-01 14:35:10 +00002915 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
2916 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002917}
2918
2919/**
2920 * xmlXPathRegisteredFuncsCleanup:
2921 * @ctxt: the XPath context
2922 *
2923 * Cleanup the XPath context data associated to registered functions
2924 */
2925void
2926xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2927 if (ctxt == NULL)
2928 return;
2929
2930 xmlHashFree(ctxt->funcHash, NULL);
2931 ctxt->funcHash = NULL;
2932}
2933
2934/************************************************************************
2935 * *
William M. Brack08171912003-12-29 02:52:11 +00002936 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00002937 * *
2938 ************************************************************************/
2939
2940/**
2941 * xmlXPathRegisterVariable:
2942 * @ctxt: the XPath context
2943 * @name: the variable name
2944 * @value: the variable value or NULL
2945 *
2946 * Register a new variable value. If @value is NULL it unregisters
2947 * the variable
2948 *
2949 * Returns 0 in case of success, -1 in case of error
2950 */
2951int
2952xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2953 xmlXPathObjectPtr value) {
2954 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2955}
2956
2957/**
2958 * xmlXPathRegisterVariableNS:
2959 * @ctxt: the XPath context
2960 * @name: the variable name
2961 * @ns_uri: the variable namespace URI
2962 * @value: the variable value or NULL
2963 *
2964 * Register a new variable value. If @value is NULL it unregisters
2965 * the variable
2966 *
2967 * Returns 0 in case of success, -1 in case of error
2968 */
2969int
2970xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2971 const xmlChar *ns_uri,
2972 xmlXPathObjectPtr value) {
2973 if (ctxt == NULL)
2974 return(-1);
2975 if (name == NULL)
2976 return(-1);
2977
2978 if (ctxt->varHash == NULL)
2979 ctxt->varHash = xmlHashCreate(0);
2980 if (ctxt->varHash == NULL)
2981 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002982 if (value == NULL)
2983 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2984 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002985 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2986 (void *) value,
2987 (xmlHashDeallocator)xmlXPathFreeObject));
2988}
2989
2990/**
2991 * xmlXPathRegisterVariableLookup:
2992 * @ctxt: the XPath context
2993 * @f: the lookup function
2994 * @data: the lookup data
2995 *
2996 * register an external mechanism to do variable lookup
2997 */
2998void
2999xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
3000 xmlXPathVariableLookupFunc f, void *data) {
3001 if (ctxt == NULL)
3002 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00003003 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00003004 ctxt->varLookupData = data;
3005}
3006
3007/**
3008 * xmlXPathVariableLookup:
3009 * @ctxt: the XPath context
3010 * @name: the variable name
3011 *
3012 * Search in the Variable array of the context for the given
3013 * variable value.
3014 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003015 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003016 */
3017xmlXPathObjectPtr
3018xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3019 if (ctxt == NULL)
3020 return(NULL);
3021
3022 if (ctxt->varLookupFunc != NULL) {
3023 xmlXPathObjectPtr ret;
3024
3025 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3026 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00003027 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003028 }
3029 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3030}
3031
3032/**
3033 * xmlXPathVariableLookupNS:
3034 * @ctxt: the XPath context
3035 * @name: the variable name
3036 * @ns_uri: the variable namespace URI
3037 *
3038 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00003039 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00003040 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003041 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003042 */
3043xmlXPathObjectPtr
3044xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3045 const xmlChar *ns_uri) {
3046 if (ctxt == NULL)
3047 return(NULL);
3048
3049 if (ctxt->varLookupFunc != NULL) {
3050 xmlXPathObjectPtr ret;
3051
3052 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3053 (ctxt->varLookupData, name, ns_uri);
3054 if (ret != NULL) return(ret);
3055 }
3056
3057 if (ctxt->varHash == NULL)
3058 return(NULL);
3059 if (name == NULL)
3060 return(NULL);
3061
Daniel Veillard8c357d52001-07-03 23:43:33 +00003062 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3063 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00003064}
3065
3066/**
3067 * xmlXPathRegisteredVariablesCleanup:
3068 * @ctxt: the XPath context
3069 *
3070 * Cleanup the XPath context data associated to registered variables
3071 */
3072void
3073xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3074 if (ctxt == NULL)
3075 return;
3076
Daniel Veillard76d66f42001-05-16 21:05:17 +00003077 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00003078 ctxt->varHash = NULL;
3079}
3080
3081/**
3082 * xmlXPathRegisterNs:
3083 * @ctxt: the XPath context
3084 * @prefix: the namespace prefix
3085 * @ns_uri: the namespace name
3086 *
3087 * Register a new namespace. If @ns_uri is NULL it unregisters
3088 * the namespace
3089 *
3090 * Returns 0 in case of success, -1 in case of error
3091 */
3092int
3093xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3094 const xmlChar *ns_uri) {
3095 if (ctxt == NULL)
3096 return(-1);
3097 if (prefix == NULL)
3098 return(-1);
3099
3100 if (ctxt->nsHash == NULL)
3101 ctxt->nsHash = xmlHashCreate(10);
3102 if (ctxt->nsHash == NULL)
3103 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003104 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003105 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003106 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003107 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003108 (xmlHashDeallocator)xmlFree));
3109}
3110
3111/**
3112 * xmlXPathNsLookup:
3113 * @ctxt: the XPath context
3114 * @prefix: the namespace prefix value
3115 *
3116 * Search in the namespace declaration array of the context for the given
3117 * namespace name associated to the given prefix
3118 *
3119 * Returns the value or NULL if not found
3120 */
3121const xmlChar *
3122xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3123 if (ctxt == NULL)
3124 return(NULL);
3125 if (prefix == NULL)
3126 return(NULL);
3127
3128#ifdef XML_XML_NAMESPACE
3129 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3130 return(XML_XML_NAMESPACE);
3131#endif
3132
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003133 if (ctxt->namespaces != NULL) {
3134 int i;
3135
3136 for (i = 0;i < ctxt->nsNr;i++) {
3137 if ((ctxt->namespaces[i] != NULL) &&
3138 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3139 return(ctxt->namespaces[i]->href);
3140 }
3141 }
Owen Taylor3473f882001-02-23 17:55:21 +00003142
3143 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3144}
3145
3146/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003147 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003148 * @ctxt: the XPath context
3149 *
3150 * Cleanup the XPath context data associated to registered variables
3151 */
3152void
3153xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3154 if (ctxt == NULL)
3155 return;
3156
Daniel Veillard42766c02002-08-22 20:52:17 +00003157 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003158 ctxt->nsHash = NULL;
3159}
3160
3161/************************************************************************
3162 * *
3163 * Routines to handle Values *
3164 * *
3165 ************************************************************************/
3166
William M. Brack08171912003-12-29 02:52:11 +00003167/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003168
3169/**
3170 * xmlXPathNewFloat:
3171 * @val: the double value
3172 *
3173 * Create a new xmlXPathObjectPtr of type double and of value @val
3174 *
3175 * Returns the newly created object.
3176 */
3177xmlXPathObjectPtr
3178xmlXPathNewFloat(double val) {
3179 xmlXPathObjectPtr ret;
3180
3181 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3182 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003183 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003184 return(NULL);
3185 }
3186 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3187 ret->type = XPATH_NUMBER;
3188 ret->floatval = val;
3189 return(ret);
3190}
3191
3192/**
3193 * xmlXPathNewBoolean:
3194 * @val: the boolean value
3195 *
3196 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3197 *
3198 * Returns the newly created object.
3199 */
3200xmlXPathObjectPtr
3201xmlXPathNewBoolean(int val) {
3202 xmlXPathObjectPtr ret;
3203
3204 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3205 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003206 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003207 return(NULL);
3208 }
3209 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3210 ret->type = XPATH_BOOLEAN;
3211 ret->boolval = (val != 0);
3212 return(ret);
3213}
3214
3215/**
3216 * xmlXPathNewString:
3217 * @val: the xmlChar * value
3218 *
3219 * Create a new xmlXPathObjectPtr of type string and of value @val
3220 *
3221 * Returns the newly created object.
3222 */
3223xmlXPathObjectPtr
3224xmlXPathNewString(const xmlChar *val) {
3225 xmlXPathObjectPtr ret;
3226
3227 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3228 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003229 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003230 return(NULL);
3231 }
3232 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3233 ret->type = XPATH_STRING;
3234 if (val != NULL)
3235 ret->stringval = xmlStrdup(val);
3236 else
3237 ret->stringval = xmlStrdup((const xmlChar *)"");
3238 return(ret);
3239}
3240
3241/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003242 * xmlXPathWrapString:
3243 * @val: the xmlChar * value
3244 *
3245 * Wraps the @val string into an XPath object.
3246 *
3247 * Returns the newly created object.
3248 */
3249xmlXPathObjectPtr
3250xmlXPathWrapString (xmlChar *val) {
3251 xmlXPathObjectPtr ret;
3252
3253 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3254 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003255 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003256 return(NULL);
3257 }
3258 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3259 ret->type = XPATH_STRING;
3260 ret->stringval = val;
3261 return(ret);
3262}
3263
3264/**
Owen Taylor3473f882001-02-23 17:55:21 +00003265 * xmlXPathNewCString:
3266 * @val: the char * value
3267 *
3268 * Create a new xmlXPathObjectPtr of type string and of value @val
3269 *
3270 * Returns the newly created object.
3271 */
3272xmlXPathObjectPtr
3273xmlXPathNewCString(const char *val) {
3274 xmlXPathObjectPtr ret;
3275
3276 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3277 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003278 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003279 return(NULL);
3280 }
3281 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3282 ret->type = XPATH_STRING;
3283 ret->stringval = xmlStrdup(BAD_CAST val);
3284 return(ret);
3285}
3286
3287/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003288 * xmlXPathWrapCString:
3289 * @val: the char * value
3290 *
3291 * Wraps a string into an XPath object.
3292 *
3293 * Returns the newly created object.
3294 */
3295xmlXPathObjectPtr
3296xmlXPathWrapCString (char * val) {
3297 return(xmlXPathWrapString((xmlChar *)(val)));
3298}
3299
3300/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003301 * xmlXPathWrapExternal:
3302 * @val: the user data
3303 *
3304 * Wraps the @val data into an XPath object.
3305 *
3306 * Returns the newly created object.
3307 */
3308xmlXPathObjectPtr
3309xmlXPathWrapExternal (void *val) {
3310 xmlXPathObjectPtr ret;
3311
3312 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3313 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003314 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003315 return(NULL);
3316 }
3317 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3318 ret->type = XPATH_USERS;
3319 ret->user = val;
3320 return(ret);
3321}
3322
3323/**
Owen Taylor3473f882001-02-23 17:55:21 +00003324 * xmlXPathObjectCopy:
3325 * @val: the original object
3326 *
3327 * allocate a new copy of a given object
3328 *
3329 * Returns the newly created object.
3330 */
3331xmlXPathObjectPtr
3332xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3333 xmlXPathObjectPtr ret;
3334
3335 if (val == NULL)
3336 return(NULL);
3337
3338 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3339 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003340 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003341 return(NULL);
3342 }
3343 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3344 switch (val->type) {
3345 case XPATH_BOOLEAN:
3346 case XPATH_NUMBER:
3347 case XPATH_POINT:
3348 case XPATH_RANGE:
3349 break;
3350 case XPATH_STRING:
3351 ret->stringval = xmlStrdup(val->stringval);
3352 break;
3353 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00003354#if 0
3355/*
3356 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
3357 this previous handling is no longer correct, and can cause some serious
3358 problems (ref. bug 145547)
3359*/
Owen Taylor3473f882001-02-23 17:55:21 +00003360 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003361 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003362 xmlNodePtr cur, tmp;
3363 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003364
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003365 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003366 top = xmlNewDoc(NULL);
3367 top->name = (char *)
3368 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003369 ret->user = top;
3370 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003371 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003372 cur = val->nodesetval->nodeTab[0]->children;
3373 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003374 tmp = xmlDocCopyNode(cur, top, 1);
3375 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003376 cur = cur->next;
3377 }
3378 }
William M. Bracke9449c52004-07-11 14:41:20 +00003379
Daniel Veillard9adc0462003-03-24 18:39:54 +00003380 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003381 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003382 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003383 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003384 break;
William M. Bracke9449c52004-07-11 14:41:20 +00003385#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003386 case XPATH_NODESET:
3387 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003388 /* Do not deallocate the copied tree value */
3389 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003390 break;
3391 case XPATH_LOCATIONSET:
3392#ifdef LIBXML_XPTR_ENABLED
3393 {
3394 xmlLocationSetPtr loc = val->user;
3395 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3396 break;
3397 }
3398#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003399 case XPATH_USERS:
3400 ret->user = val->user;
3401 break;
3402 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003403 xmlGenericError(xmlGenericErrorContext,
3404 "xmlXPathObjectCopy: unsupported type %d\n",
3405 val->type);
3406 break;
3407 }
3408 return(ret);
3409}
3410
3411/**
3412 * xmlXPathFreeObject:
3413 * @obj: the object to free
3414 *
3415 * Free up an xmlXPathObjectPtr object.
3416 */
3417void
3418xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3419 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003420 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003421 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00003422#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003423 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003424 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003425 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003426 } else
3427#endif
3428 if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003429 xmlXPathFreeValueTree(obj->nodesetval);
3430 } else {
3431 if (obj->nodesetval != NULL)
3432 xmlXPathFreeNodeSet(obj->nodesetval);
3433 }
Owen Taylor3473f882001-02-23 17:55:21 +00003434#ifdef LIBXML_XPTR_ENABLED
3435 } else if (obj->type == XPATH_LOCATIONSET) {
3436 if (obj->user != NULL)
3437 xmlXPtrFreeLocationSet(obj->user);
3438#endif
3439 } else if (obj->type == XPATH_STRING) {
3440 if (obj->stringval != NULL)
3441 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003442 }
3443
Owen Taylor3473f882001-02-23 17:55:21 +00003444 xmlFree(obj);
3445}
3446
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003447
3448/************************************************************************
3449 * *
3450 * Type Casting Routines *
3451 * *
3452 ************************************************************************/
3453
3454/**
3455 * xmlXPathCastBooleanToString:
3456 * @val: a boolean
3457 *
3458 * Converts a boolean to its string value.
3459 *
3460 * Returns a newly allocated string.
3461 */
3462xmlChar *
3463xmlXPathCastBooleanToString (int val) {
3464 xmlChar *ret;
3465 if (val)
3466 ret = xmlStrdup((const xmlChar *) "true");
3467 else
3468 ret = xmlStrdup((const xmlChar *) "false");
3469 return(ret);
3470}
3471
3472/**
3473 * xmlXPathCastNumberToString:
3474 * @val: a number
3475 *
3476 * Converts a number to its string value.
3477 *
3478 * Returns a newly allocated string.
3479 */
3480xmlChar *
3481xmlXPathCastNumberToString (double val) {
3482 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003483 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003484 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003485 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003486 break;
3487 case -1:
3488 ret = xmlStrdup((const xmlChar *) "-Infinity");
3489 break;
3490 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003491 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003492 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003493 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3494 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003495 } else {
3496 /* could be improved */
3497 char buf[100];
3498 xmlXPathFormatNumber(val, buf, 100);
3499 ret = xmlStrdup((const xmlChar *) buf);
3500 }
3501 }
3502 return(ret);
3503}
3504
3505/**
3506 * xmlXPathCastNodeToString:
3507 * @node: a node
3508 *
3509 * Converts a node to its string value.
3510 *
3511 * Returns a newly allocated string.
3512 */
3513xmlChar *
3514xmlXPathCastNodeToString (xmlNodePtr node) {
3515 return(xmlNodeGetContent(node));
3516}
3517
3518/**
3519 * xmlXPathCastNodeSetToString:
3520 * @ns: a node-set
3521 *
3522 * Converts a node-set to its string value.
3523 *
3524 * Returns a newly allocated string.
3525 */
3526xmlChar *
3527xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3528 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3529 return(xmlStrdup((const xmlChar *) ""));
3530
3531 xmlXPathNodeSetSort(ns);
3532 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3533}
3534
3535/**
3536 * xmlXPathCastToString:
3537 * @val: an XPath object
3538 *
3539 * Converts an existing object to its string() equivalent
3540 *
3541 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003542 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003543 * string object).
3544 */
3545xmlChar *
3546xmlXPathCastToString(xmlXPathObjectPtr val) {
3547 xmlChar *ret = NULL;
3548
3549 if (val == NULL)
3550 return(xmlStrdup((const xmlChar *) ""));
3551 switch (val->type) {
3552 case XPATH_UNDEFINED:
3553#ifdef DEBUG_EXPR
3554 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3555#endif
3556 ret = xmlStrdup((const xmlChar *) "");
3557 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003558 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003559 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003560 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3561 break;
3562 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003563 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003564 case XPATH_BOOLEAN:
3565 ret = xmlXPathCastBooleanToString(val->boolval);
3566 break;
3567 case XPATH_NUMBER: {
3568 ret = xmlXPathCastNumberToString(val->floatval);
3569 break;
3570 }
3571 case XPATH_USERS:
3572 case XPATH_POINT:
3573 case XPATH_RANGE:
3574 case XPATH_LOCATIONSET:
3575 TODO
3576 ret = xmlStrdup((const xmlChar *) "");
3577 break;
3578 }
3579 return(ret);
3580}
3581
3582/**
3583 * xmlXPathConvertString:
3584 * @val: an XPath object
3585 *
3586 * Converts an existing object to its string() equivalent
3587 *
3588 * Returns the new object, the old one is freed (or the operation
3589 * is done directly on @val)
3590 */
3591xmlXPathObjectPtr
3592xmlXPathConvertString(xmlXPathObjectPtr val) {
3593 xmlChar *res = NULL;
3594
3595 if (val == NULL)
3596 return(xmlXPathNewCString(""));
3597
3598 switch (val->type) {
3599 case XPATH_UNDEFINED:
3600#ifdef DEBUG_EXPR
3601 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3602#endif
3603 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003604 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003605 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003606 res = xmlXPathCastNodeSetToString(val->nodesetval);
3607 break;
3608 case XPATH_STRING:
3609 return(val);
3610 case XPATH_BOOLEAN:
3611 res = xmlXPathCastBooleanToString(val->boolval);
3612 break;
3613 case XPATH_NUMBER:
3614 res = xmlXPathCastNumberToString(val->floatval);
3615 break;
3616 case XPATH_USERS:
3617 case XPATH_POINT:
3618 case XPATH_RANGE:
3619 case XPATH_LOCATIONSET:
3620 TODO;
3621 break;
3622 }
3623 xmlXPathFreeObject(val);
3624 if (res == NULL)
3625 return(xmlXPathNewCString(""));
3626 return(xmlXPathWrapString(res));
3627}
3628
3629/**
3630 * xmlXPathCastBooleanToNumber:
3631 * @val: a boolean
3632 *
3633 * Converts a boolean to its number value
3634 *
3635 * Returns the number value
3636 */
3637double
3638xmlXPathCastBooleanToNumber(int val) {
3639 if (val)
3640 return(1.0);
3641 return(0.0);
3642}
3643
3644/**
3645 * xmlXPathCastStringToNumber:
3646 * @val: a string
3647 *
3648 * Converts a string to its number value
3649 *
3650 * Returns the number value
3651 */
3652double
3653xmlXPathCastStringToNumber(const xmlChar * val) {
3654 return(xmlXPathStringEvalNumber(val));
3655}
3656
3657/**
3658 * xmlXPathCastNodeToNumber:
3659 * @node: a node
3660 *
3661 * Converts a node to its number value
3662 *
3663 * Returns the number value
3664 */
3665double
3666xmlXPathCastNodeToNumber (xmlNodePtr node) {
3667 xmlChar *strval;
3668 double ret;
3669
3670 if (node == NULL)
3671 return(xmlXPathNAN);
3672 strval = xmlXPathCastNodeToString(node);
3673 if (strval == NULL)
3674 return(xmlXPathNAN);
3675 ret = xmlXPathCastStringToNumber(strval);
3676 xmlFree(strval);
3677
3678 return(ret);
3679}
3680
3681/**
3682 * xmlXPathCastNodeSetToNumber:
3683 * @ns: a node-set
3684 *
3685 * Converts a node-set to its number value
3686 *
3687 * Returns the number value
3688 */
3689double
3690xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3691 xmlChar *str;
3692 double ret;
3693
3694 if (ns == NULL)
3695 return(xmlXPathNAN);
3696 str = xmlXPathCastNodeSetToString(ns);
3697 ret = xmlXPathCastStringToNumber(str);
3698 xmlFree(str);
3699 return(ret);
3700}
3701
3702/**
3703 * xmlXPathCastToNumber:
3704 * @val: an XPath object
3705 *
3706 * Converts an XPath object to its number value
3707 *
3708 * Returns the number value
3709 */
3710double
3711xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3712 double ret = 0.0;
3713
3714 if (val == NULL)
3715 return(xmlXPathNAN);
3716 switch (val->type) {
3717 case XPATH_UNDEFINED:
3718#ifdef DEGUB_EXPR
3719 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3720#endif
3721 ret = xmlXPathNAN;
3722 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003723 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003724 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003725 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3726 break;
3727 case XPATH_STRING:
3728 ret = xmlXPathCastStringToNumber(val->stringval);
3729 break;
3730 case XPATH_NUMBER:
3731 ret = val->floatval;
3732 break;
3733 case XPATH_BOOLEAN:
3734 ret = xmlXPathCastBooleanToNumber(val->boolval);
3735 break;
3736 case XPATH_USERS:
3737 case XPATH_POINT:
3738 case XPATH_RANGE:
3739 case XPATH_LOCATIONSET:
3740 TODO;
3741 ret = xmlXPathNAN;
3742 break;
3743 }
3744 return(ret);
3745}
3746
3747/**
3748 * xmlXPathConvertNumber:
3749 * @val: an XPath object
3750 *
3751 * Converts an existing object to its number() equivalent
3752 *
3753 * Returns the new object, the old one is freed (or the operation
3754 * is done directly on @val)
3755 */
3756xmlXPathObjectPtr
3757xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3758 xmlXPathObjectPtr ret;
3759
3760 if (val == NULL)
3761 return(xmlXPathNewFloat(0.0));
3762 if (val->type == XPATH_NUMBER)
3763 return(val);
3764 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3765 xmlXPathFreeObject(val);
3766 return(ret);
3767}
3768
3769/**
3770 * xmlXPathCastNumberToBoolean:
3771 * @val: a number
3772 *
3773 * Converts a number to its boolean value
3774 *
3775 * Returns the boolean value
3776 */
3777int
3778xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003779 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003780 return(0);
3781 return(1);
3782}
3783
3784/**
3785 * xmlXPathCastStringToBoolean:
3786 * @val: a string
3787 *
3788 * Converts a string to its boolean value
3789 *
3790 * Returns the boolean value
3791 */
3792int
3793xmlXPathCastStringToBoolean (const xmlChar *val) {
3794 if ((val == NULL) || (xmlStrlen(val) == 0))
3795 return(0);
3796 return(1);
3797}
3798
3799/**
3800 * xmlXPathCastNodeSetToBoolean:
3801 * @ns: a node-set
3802 *
3803 * Converts a node-set to its boolean value
3804 *
3805 * Returns the boolean value
3806 */
3807int
3808xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3809 if ((ns == NULL) || (ns->nodeNr == 0))
3810 return(0);
3811 return(1);
3812}
3813
3814/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003815 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003816 * @val: an XPath object
3817 *
3818 * Converts an XPath object to its boolean value
3819 *
3820 * Returns the boolean value
3821 */
3822int
3823xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3824 int ret = 0;
3825
3826 if (val == NULL)
3827 return(0);
3828 switch (val->type) {
3829 case XPATH_UNDEFINED:
3830#ifdef DEBUG_EXPR
3831 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3832#endif
3833 ret = 0;
3834 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003835 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003836 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003837 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3838 break;
3839 case XPATH_STRING:
3840 ret = xmlXPathCastStringToBoolean(val->stringval);
3841 break;
3842 case XPATH_NUMBER:
3843 ret = xmlXPathCastNumberToBoolean(val->floatval);
3844 break;
3845 case XPATH_BOOLEAN:
3846 ret = val->boolval;
3847 break;
3848 case XPATH_USERS:
3849 case XPATH_POINT:
3850 case XPATH_RANGE:
3851 case XPATH_LOCATIONSET:
3852 TODO;
3853 ret = 0;
3854 break;
3855 }
3856 return(ret);
3857}
3858
3859
3860/**
3861 * xmlXPathConvertBoolean:
3862 * @val: an XPath object
3863 *
3864 * Converts an existing object to its boolean() equivalent
3865 *
3866 * Returns the new object, the old one is freed (or the operation
3867 * is done directly on @val)
3868 */
3869xmlXPathObjectPtr
3870xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3871 xmlXPathObjectPtr ret;
3872
3873 if (val == NULL)
3874 return(xmlXPathNewBoolean(0));
3875 if (val->type == XPATH_BOOLEAN)
3876 return(val);
3877 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3878 xmlXPathFreeObject(val);
3879 return(ret);
3880}
3881
Owen Taylor3473f882001-02-23 17:55:21 +00003882/************************************************************************
3883 * *
3884 * Routines to handle XPath contexts *
3885 * *
3886 ************************************************************************/
3887
3888/**
3889 * xmlXPathNewContext:
3890 * @doc: the XML document
3891 *
3892 * Create a new xmlXPathContext
3893 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003894 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003895 */
3896xmlXPathContextPtr
3897xmlXPathNewContext(xmlDocPtr doc) {
3898 xmlXPathContextPtr ret;
3899
3900 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3901 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003902 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003903 return(NULL);
3904 }
3905 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3906 ret->doc = doc;
3907 ret->node = NULL;
3908
3909 ret->varHash = NULL;
3910
3911 ret->nb_types = 0;
3912 ret->max_types = 0;
3913 ret->types = NULL;
3914
3915 ret->funcHash = xmlHashCreate(0);
3916
3917 ret->nb_axis = 0;
3918 ret->max_axis = 0;
3919 ret->axis = NULL;
3920
3921 ret->nsHash = NULL;
3922 ret->user = NULL;
3923
3924 ret->contextSize = -1;
3925 ret->proximityPosition = -1;
3926
3927 xmlXPathRegisterAllFunctions(ret);
3928
3929 return(ret);
3930}
3931
3932/**
3933 * xmlXPathFreeContext:
3934 * @ctxt: the context to free
3935 *
3936 * Free up an xmlXPathContext
3937 */
3938void
3939xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00003940 if (ctxt == NULL) return;
3941
Owen Taylor3473f882001-02-23 17:55:21 +00003942 xmlXPathRegisteredNsCleanup(ctxt);
3943 xmlXPathRegisteredFuncsCleanup(ctxt);
3944 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00003945 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00003946 xmlFree(ctxt);
3947}
3948
3949/************************************************************************
3950 * *
3951 * Routines to handle XPath parser contexts *
3952 * *
3953 ************************************************************************/
3954
3955#define CHECK_CTXT(ctxt) \
3956 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00003957 __xmlRaiseError(NULL, NULL, NULL, \
3958 NULL, NULL, XML_FROM_XPATH, \
3959 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
3960 __FILE__, __LINE__, \
3961 NULL, NULL, NULL, 0, 0, \
3962 "NULL context pointer\n"); \
3963 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00003964 } \
3965
3966
3967#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00003968 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
3969 (ctxt->doc->children == NULL)) { \
3970 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00003971 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00003972 }
Owen Taylor3473f882001-02-23 17:55:21 +00003973
3974
3975/**
3976 * xmlXPathNewParserContext:
3977 * @str: the XPath expression
3978 * @ctxt: the XPath context
3979 *
3980 * Create a new xmlXPathParserContext
3981 *
3982 * Returns the xmlXPathParserContext just allocated.
3983 */
3984xmlXPathParserContextPtr
3985xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3986 xmlXPathParserContextPtr ret;
3987
3988 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3989 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003990 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003991 return(NULL);
3992 }
3993 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3994 ret->cur = ret->base = str;
3995 ret->context = ctxt;
3996
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003997 ret->comp = xmlXPathNewCompExpr();
3998 if (ret->comp == NULL) {
3999 xmlFree(ret->valueTab);
4000 xmlFree(ret);
4001 return(NULL);
4002 }
Daniel Veillard4773df22004-01-23 13:15:13 +00004003 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4004 ret->comp->dict = ctxt->dict;
4005 xmlDictReference(ret->comp->dict);
4006 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004007
4008 return(ret);
4009}
4010
4011/**
4012 * xmlXPathCompParserContext:
4013 * @comp: the XPath compiled expression
4014 * @ctxt: the XPath context
4015 *
4016 * Create a new xmlXPathParserContext when processing a compiled expression
4017 *
4018 * Returns the xmlXPathParserContext just allocated.
4019 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004020static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004021xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4022 xmlXPathParserContextPtr ret;
4023
4024 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4025 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004026 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004027 return(NULL);
4028 }
4029 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4030
Owen Taylor3473f882001-02-23 17:55:21 +00004031 /* Allocate the value stack */
4032 ret->valueTab = (xmlXPathObjectPtr *)
4033 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004034 if (ret->valueTab == NULL) {
4035 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004036 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004037 return(NULL);
4038 }
Owen Taylor3473f882001-02-23 17:55:21 +00004039 ret->valueNr = 0;
4040 ret->valueMax = 10;
4041 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004042
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004043 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004044 ret->comp = comp;
4045
Owen Taylor3473f882001-02-23 17:55:21 +00004046 return(ret);
4047}
4048
4049/**
4050 * xmlXPathFreeParserContext:
4051 * @ctxt: the context to free
4052 *
4053 * Free up an xmlXPathParserContext
4054 */
4055void
4056xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
4057 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004058 xmlFree(ctxt->valueTab);
4059 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00004060 if (ctxt->comp != NULL) {
4061#ifdef XPATH_STREAMING
4062 if (ctxt->comp->stream != NULL) {
4063 xmlFreePatternList(ctxt->comp->stream);
4064 ctxt->comp->stream = NULL;
4065 }
4066#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004067 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00004068 }
Owen Taylor3473f882001-02-23 17:55:21 +00004069 xmlFree(ctxt);
4070}
4071
4072/************************************************************************
4073 * *
4074 * The implicit core function library *
4075 * *
4076 ************************************************************************/
4077
Owen Taylor3473f882001-02-23 17:55:21 +00004078/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004079 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00004080 * @node: a node pointer
4081 *
4082 * Function computing the beginning of the string value of the node,
4083 * used to speed up comparisons
4084 *
4085 * Returns an int usable as a hash
4086 */
4087static unsigned int
4088xmlXPathNodeValHash(xmlNodePtr node) {
4089 int len = 2;
4090 const xmlChar * string = NULL;
4091 xmlNodePtr tmp = NULL;
4092 unsigned int ret = 0;
4093
4094 if (node == NULL)
4095 return(0);
4096
Daniel Veillard9adc0462003-03-24 18:39:54 +00004097 if (node->type == XML_DOCUMENT_NODE) {
4098 tmp = xmlDocGetRootElement((xmlDocPtr) node);
4099 if (tmp == NULL)
4100 node = node->children;
4101 else
4102 node = tmp;
4103
4104 if (node == NULL)
4105 return(0);
4106 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004107
4108 switch (node->type) {
4109 case XML_COMMENT_NODE:
4110 case XML_PI_NODE:
4111 case XML_CDATA_SECTION_NODE:
4112 case XML_TEXT_NODE:
4113 string = node->content;
4114 if (string == NULL)
4115 return(0);
4116 if (string[0] == 0)
4117 return(0);
4118 return(((unsigned int) string[0]) +
4119 (((unsigned int) string[1]) << 8));
4120 case XML_NAMESPACE_DECL:
4121 string = ((xmlNsPtr)node)->href;
4122 if (string == NULL)
4123 return(0);
4124 if (string[0] == 0)
4125 return(0);
4126 return(((unsigned int) string[0]) +
4127 (((unsigned int) string[1]) << 8));
4128 case XML_ATTRIBUTE_NODE:
4129 tmp = ((xmlAttrPtr) node)->children;
4130 break;
4131 case XML_ELEMENT_NODE:
4132 tmp = node->children;
4133 break;
4134 default:
4135 return(0);
4136 }
4137 while (tmp != NULL) {
4138 switch (tmp->type) {
4139 case XML_COMMENT_NODE:
4140 case XML_PI_NODE:
4141 case XML_CDATA_SECTION_NODE:
4142 case XML_TEXT_NODE:
4143 string = tmp->content;
4144 break;
4145 case XML_NAMESPACE_DECL:
4146 string = ((xmlNsPtr)tmp)->href;
4147 break;
4148 default:
4149 break;
4150 }
4151 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004152 if (len == 1) {
4153 return(ret + (((unsigned int) string[0]) << 8));
4154 }
4155 if (string[1] == 0) {
4156 len = 1;
4157 ret = (unsigned int) string[0];
4158 } else {
4159 return(((unsigned int) string[0]) +
4160 (((unsigned int) string[1]) << 8));
4161 }
4162 }
4163 /*
4164 * Skip to next node
4165 */
4166 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4167 if (tmp->children->type != XML_ENTITY_DECL) {
4168 tmp = tmp->children;
4169 continue;
4170 }
4171 }
4172 if (tmp == node)
4173 break;
4174
4175 if (tmp->next != NULL) {
4176 tmp = tmp->next;
4177 continue;
4178 }
4179
4180 do {
4181 tmp = tmp->parent;
4182 if (tmp == NULL)
4183 break;
4184 if (tmp == node) {
4185 tmp = NULL;
4186 break;
4187 }
4188 if (tmp->next != NULL) {
4189 tmp = tmp->next;
4190 break;
4191 }
4192 } while (tmp != NULL);
4193 }
4194 return(ret);
4195}
4196
4197/**
4198 * xmlXPathStringHash:
4199 * @string: a string
4200 *
4201 * Function computing the beginning of the string value of the node,
4202 * used to speed up comparisons
4203 *
4204 * Returns an int usable as a hash
4205 */
4206static unsigned int
4207xmlXPathStringHash(const xmlChar * string) {
4208 if (string == NULL)
4209 return((unsigned int) 0);
4210 if (string[0] == 0)
4211 return(0);
4212 return(((unsigned int) string[0]) +
4213 (((unsigned int) string[1]) << 8));
4214}
4215
4216/**
Owen Taylor3473f882001-02-23 17:55:21 +00004217 * xmlXPathCompareNodeSetFloat:
4218 * @ctxt: the XPath Parser context
4219 * @inf: less than (1) or greater than (0)
4220 * @strict: is the comparison strict
4221 * @arg: the node set
4222 * @f: the value
4223 *
4224 * Implement the compare operation between a nodeset and a number
4225 * @ns < @val (1, 1, ...
4226 * @ns <= @val (1, 0, ...
4227 * @ns > @val (0, 1, ...
4228 * @ns >= @val (0, 0, ...
4229 *
4230 * If one object to be compared is a node-set and the other is a number,
4231 * then the comparison will be true if and only if there is a node in the
4232 * node-set such that the result of performing the comparison on the number
4233 * to be compared and on the result of converting the string-value of that
4234 * node to a number using the number function is true.
4235 *
4236 * Returns 0 or 1 depending on the results of the test.
4237 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004238static int
Owen Taylor3473f882001-02-23 17:55:21 +00004239xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4240 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4241 int i, ret = 0;
4242 xmlNodeSetPtr ns;
4243 xmlChar *str2;
4244
4245 if ((f == NULL) || (arg == NULL) ||
4246 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4247 xmlXPathFreeObject(arg);
4248 xmlXPathFreeObject(f);
4249 return(0);
4250 }
4251 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004252 if (ns != NULL) {
4253 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004254 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004255 if (str2 != NULL) {
4256 valuePush(ctxt,
4257 xmlXPathNewString(str2));
4258 xmlFree(str2);
4259 xmlXPathNumberFunction(ctxt, 1);
4260 valuePush(ctxt, xmlXPathObjectCopy(f));
4261 ret = xmlXPathCompareValues(ctxt, inf, strict);
4262 if (ret)
4263 break;
4264 }
4265 }
Owen Taylor3473f882001-02-23 17:55:21 +00004266 }
4267 xmlXPathFreeObject(arg);
4268 xmlXPathFreeObject(f);
4269 return(ret);
4270}
4271
4272/**
4273 * xmlXPathCompareNodeSetString:
4274 * @ctxt: the XPath Parser context
4275 * @inf: less than (1) or greater than (0)
4276 * @strict: is the comparison strict
4277 * @arg: the node set
4278 * @s: the value
4279 *
4280 * Implement the compare operation between a nodeset and a string
4281 * @ns < @val (1, 1, ...
4282 * @ns <= @val (1, 0, ...
4283 * @ns > @val (0, 1, ...
4284 * @ns >= @val (0, 0, ...
4285 *
4286 * If one object to be compared is a node-set and the other is a string,
4287 * then the comparison will be true if and only if there is a node in
4288 * the node-set such that the result of performing the comparison on the
4289 * string-value of the node and the other string is true.
4290 *
4291 * Returns 0 or 1 depending on the results of the test.
4292 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004293static int
Owen Taylor3473f882001-02-23 17:55:21 +00004294xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4295 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4296 int i, ret = 0;
4297 xmlNodeSetPtr ns;
4298 xmlChar *str2;
4299
4300 if ((s == NULL) || (arg == NULL) ||
4301 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4302 xmlXPathFreeObject(arg);
4303 xmlXPathFreeObject(s);
4304 return(0);
4305 }
4306 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004307 if (ns != NULL) {
4308 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004309 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004310 if (str2 != NULL) {
4311 valuePush(ctxt,
4312 xmlXPathNewString(str2));
4313 xmlFree(str2);
4314 valuePush(ctxt, xmlXPathObjectCopy(s));
4315 ret = xmlXPathCompareValues(ctxt, inf, strict);
4316 if (ret)
4317 break;
4318 }
4319 }
Owen Taylor3473f882001-02-23 17:55:21 +00004320 }
4321 xmlXPathFreeObject(arg);
4322 xmlXPathFreeObject(s);
4323 return(ret);
4324}
4325
4326/**
4327 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004328 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004329 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004330 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004331 * @arg2: the second node set object
4332 *
4333 * Implement the compare operation on nodesets:
4334 *
4335 * If both objects to be compared are node-sets, then the comparison
4336 * will be true if and only if there is a node in the first node-set
4337 * and a node in the second node-set such that the result of performing
4338 * the comparison on the string-values of the two nodes is true.
4339 * ....
4340 * When neither object to be compared is a node-set and the operator
4341 * is <=, <, >= or >, then the objects are compared by converting both
4342 * objects to numbers and comparing the numbers according to IEEE 754.
4343 * ....
4344 * The number function converts its argument to a number as follows:
4345 * - a string that consists of optional whitespace followed by an
4346 * optional minus sign followed by a Number followed by whitespace
4347 * is converted to the IEEE 754 number that is nearest (according
4348 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4349 * represented by the string; any other string is converted to NaN
4350 *
4351 * Conclusion all nodes need to be converted first to their string value
4352 * and then the comparison must be done when possible
4353 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004354static int
4355xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004356 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4357 int i, j, init = 0;
4358 double val1;
4359 double *values2;
4360 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004361 xmlNodeSetPtr ns1;
4362 xmlNodeSetPtr ns2;
4363
4364 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004365 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4366 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004367 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004368 }
Owen Taylor3473f882001-02-23 17:55:21 +00004369 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004370 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4371 xmlXPathFreeObject(arg1);
4372 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004373 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004374 }
Owen Taylor3473f882001-02-23 17:55:21 +00004375
4376 ns1 = arg1->nodesetval;
4377 ns2 = arg2->nodesetval;
4378
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004379 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004380 xmlXPathFreeObject(arg1);
4381 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004382 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004383 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004384 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004385 xmlXPathFreeObject(arg1);
4386 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004387 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004388 }
Owen Taylor3473f882001-02-23 17:55:21 +00004389
4390 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4391 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004392 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004393 xmlXPathFreeObject(arg1);
4394 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004395 return(0);
4396 }
4397 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004398 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004399 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004400 continue;
4401 for (j = 0;j < ns2->nodeNr;j++) {
4402 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004403 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004404 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004405 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004406 continue;
4407 if (inf && strict)
4408 ret = (val1 < values2[j]);
4409 else if (inf && !strict)
4410 ret = (val1 <= values2[j]);
4411 else if (!inf && strict)
4412 ret = (val1 > values2[j]);
4413 else if (!inf && !strict)
4414 ret = (val1 >= values2[j]);
4415 if (ret)
4416 break;
4417 }
4418 if (ret)
4419 break;
4420 init = 1;
4421 }
4422 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004423 xmlXPathFreeObject(arg1);
4424 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004425 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004426}
4427
4428/**
4429 * xmlXPathCompareNodeSetValue:
4430 * @ctxt: the XPath Parser context
4431 * @inf: less than (1) or greater than (0)
4432 * @strict: is the comparison strict
4433 * @arg: the node set
4434 * @val: the value
4435 *
4436 * Implement the compare operation between a nodeset and a value
4437 * @ns < @val (1, 1, ...
4438 * @ns <= @val (1, 0, ...
4439 * @ns > @val (0, 1, ...
4440 * @ns >= @val (0, 0, ...
4441 *
4442 * If one object to be compared is a node-set and the other is a boolean,
4443 * then the comparison will be true if and only if the result of performing
4444 * the comparison on the boolean and on the result of converting
4445 * the node-set to a boolean using the boolean function is true.
4446 *
4447 * Returns 0 or 1 depending on the results of the test.
4448 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004449static int
Owen Taylor3473f882001-02-23 17:55:21 +00004450xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4451 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4452 if ((val == NULL) || (arg == NULL) ||
4453 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4454 return(0);
4455
4456 switch(val->type) {
4457 case XPATH_NUMBER:
4458 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4459 case XPATH_NODESET:
4460 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004461 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004462 case XPATH_STRING:
4463 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4464 case XPATH_BOOLEAN:
4465 valuePush(ctxt, arg);
4466 xmlXPathBooleanFunction(ctxt, 1);
4467 valuePush(ctxt, val);
4468 return(xmlXPathCompareValues(ctxt, inf, strict));
4469 default:
4470 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004471 }
4472 return(0);
4473}
4474
4475/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004476 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004477 * @arg: the nodeset object argument
4478 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004479 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004480 *
4481 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4482 * If one object to be compared is a node-set and the other is a string,
4483 * then the comparison will be true if and only if there is a node in
4484 * the node-set such that the result of performing the comparison on the
4485 * string-value of the node and the other string is true.
4486 *
4487 * Returns 0 or 1 depending on the results of the test.
4488 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004489static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004490xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004491{
Owen Taylor3473f882001-02-23 17:55:21 +00004492 int i;
4493 xmlNodeSetPtr ns;
4494 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004495 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004496
4497 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004498 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4499 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004500 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004501 /*
4502 * A NULL nodeset compared with a string is always false
4503 * (since there is no node equal, and no node not equal)
4504 */
4505 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004506 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004507 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004508 for (i = 0; i < ns->nodeNr; i++) {
4509 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4510 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4511 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4512 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004513 if (neq)
4514 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004515 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004516 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4517 if (neq)
4518 continue;
4519 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004520 } else if (neq) {
4521 if (str2 != NULL)
4522 xmlFree(str2);
4523 return (1);
4524 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004525 if (str2 != NULL)
4526 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004527 } else if (neq)
4528 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004529 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004530 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004531}
4532
4533/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004534 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004535 * @arg: the nodeset object argument
4536 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004537 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004538 *
4539 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4540 * If one object to be compared is a node-set and the other is a number,
4541 * then the comparison will be true if and only if there is a node in
4542 * the node-set such that the result of performing the comparison on the
4543 * number to be compared and on the result of converting the string-value
4544 * of that node to a number using the number function is true.
4545 *
4546 * Returns 0 or 1 depending on the results of the test.
4547 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004548static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004549xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4550 xmlXPathObjectPtr arg, double f, int neq) {
4551 int i, ret=0;
4552 xmlNodeSetPtr ns;
4553 xmlChar *str2;
4554 xmlXPathObjectPtr val;
4555 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004556
4557 if ((arg == NULL) ||
4558 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4559 return(0);
4560
William M. Brack0c022ad2002-07-12 00:56:01 +00004561 ns = arg->nodesetval;
4562 if (ns != NULL) {
4563 for (i=0;i<ns->nodeNr;i++) {
4564 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4565 if (str2 != NULL) {
4566 valuePush(ctxt, xmlXPathNewString(str2));
4567 xmlFree(str2);
4568 xmlXPathNumberFunction(ctxt, 1);
4569 val = valuePop(ctxt);
4570 v = val->floatval;
4571 xmlXPathFreeObject(val);
4572 if (!xmlXPathIsNaN(v)) {
4573 if ((!neq) && (v==f)) {
4574 ret = 1;
4575 break;
4576 } else if ((neq) && (v!=f)) {
4577 ret = 1;
4578 break;
4579 }
4580 }
4581 }
4582 }
4583 }
4584
4585 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004586}
4587
4588
4589/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004590 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004591 * @arg1: first nodeset object argument
4592 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004593 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004594 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004595 * Implement the equal / not equal operation on XPath nodesets:
4596 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004597 * If both objects to be compared are node-sets, then the comparison
4598 * will be true if and only if there is a node in the first node-set and
4599 * a node in the second node-set such that the result of performing the
4600 * comparison on the string-values of the two nodes is true.
4601 *
4602 * (needless to say, this is a costly operation)
4603 *
4604 * Returns 0 or 1 depending on the results of the test.
4605 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004606static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004607xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004608 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004609 unsigned int *hashs1;
4610 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004611 xmlChar **values1;
4612 xmlChar **values2;
4613 int ret = 0;
4614 xmlNodeSetPtr ns1;
4615 xmlNodeSetPtr ns2;
4616
4617 if ((arg1 == NULL) ||
4618 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4619 return(0);
4620 if ((arg2 == NULL) ||
4621 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4622 return(0);
4623
4624 ns1 = arg1->nodesetval;
4625 ns2 = arg2->nodesetval;
4626
Daniel Veillard911f49a2001-04-07 15:39:35 +00004627 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004628 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004629 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004630 return(0);
4631
4632 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004633 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004634 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004635 if (neq == 0)
4636 for (i = 0;i < ns1->nodeNr;i++)
4637 for (j = 0;j < ns2->nodeNr;j++)
4638 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4639 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004640
4641 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004642 if (values1 == NULL) {
4643 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004644 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004645 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004646 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4647 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004648 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004649 xmlFree(values1);
4650 return(0);
4651 }
Owen Taylor3473f882001-02-23 17:55:21 +00004652 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4653 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4654 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004655 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004656 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004657 xmlFree(values1);
4658 return(0);
4659 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004660 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4661 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004662 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004663 xmlFree(hashs1);
4664 xmlFree(values1);
4665 xmlFree(values2);
4666 return(0);
4667 }
Owen Taylor3473f882001-02-23 17:55:21 +00004668 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4669 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004670 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004671 for (j = 0;j < ns2->nodeNr;j++) {
4672 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004673 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004674 if (hashs1[i] != hashs2[j]) {
4675 if (neq) {
4676 ret = 1;
4677 break;
4678 }
4679 }
4680 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004681 if (values1[i] == NULL)
4682 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4683 if (values2[j] == NULL)
4684 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004685 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004686 if (ret)
4687 break;
4688 }
Owen Taylor3473f882001-02-23 17:55:21 +00004689 }
4690 if (ret)
4691 break;
4692 }
4693 for (i = 0;i < ns1->nodeNr;i++)
4694 if (values1[i] != NULL)
4695 xmlFree(values1[i]);
4696 for (j = 0;j < ns2->nodeNr;j++)
4697 if (values2[j] != NULL)
4698 xmlFree(values2[j]);
4699 xmlFree(values1);
4700 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004701 xmlFree(hashs1);
4702 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004703 return(ret);
4704}
4705
William M. Brack0c022ad2002-07-12 00:56:01 +00004706static int
4707xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4708 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004709 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004710 /*
4711 *At this point we are assured neither arg1 nor arg2
4712 *is a nodeset, so we can just pick the appropriate routine.
4713 */
Owen Taylor3473f882001-02-23 17:55:21 +00004714 switch (arg1->type) {
4715 case XPATH_UNDEFINED:
4716#ifdef DEBUG_EXPR
4717 xmlGenericError(xmlGenericErrorContext,
4718 "Equal: undefined\n");
4719#endif
4720 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004721 case XPATH_BOOLEAN:
4722 switch (arg2->type) {
4723 case XPATH_UNDEFINED:
4724#ifdef DEBUG_EXPR
4725 xmlGenericError(xmlGenericErrorContext,
4726 "Equal: undefined\n");
4727#endif
4728 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004729 case XPATH_BOOLEAN:
4730#ifdef DEBUG_EXPR
4731 xmlGenericError(xmlGenericErrorContext,
4732 "Equal: %d boolean %d \n",
4733 arg1->boolval, arg2->boolval);
4734#endif
4735 ret = (arg1->boolval == arg2->boolval);
4736 break;
4737 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004738 ret = (arg1->boolval ==
4739 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004740 break;
4741 case XPATH_STRING:
4742 if ((arg2->stringval == NULL) ||
4743 (arg2->stringval[0] == 0)) ret = 0;
4744 else
4745 ret = 1;
4746 ret = (arg1->boolval == ret);
4747 break;
4748 case XPATH_USERS:
4749 case XPATH_POINT:
4750 case XPATH_RANGE:
4751 case XPATH_LOCATIONSET:
4752 TODO
4753 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004754 case XPATH_NODESET:
4755 case XPATH_XSLT_TREE:
4756 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004757 }
4758 break;
4759 case XPATH_NUMBER:
4760 switch (arg2->type) {
4761 case XPATH_UNDEFINED:
4762#ifdef DEBUG_EXPR
4763 xmlGenericError(xmlGenericErrorContext,
4764 "Equal: undefined\n");
4765#endif
4766 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004767 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004768 ret = (arg2->boolval==
4769 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004770 break;
4771 case XPATH_STRING:
4772 valuePush(ctxt, arg2);
4773 xmlXPathNumberFunction(ctxt, 1);
4774 arg2 = valuePop(ctxt);
4775 /* no break on purpose */
4776 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004777 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004778 if (xmlXPathIsNaN(arg1->floatval) ||
4779 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004780 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004781 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4782 if (xmlXPathIsInf(arg2->floatval) == 1)
4783 ret = 1;
4784 else
4785 ret = 0;
4786 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4787 if (xmlXPathIsInf(arg2->floatval) == -1)
4788 ret = 1;
4789 else
4790 ret = 0;
4791 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4792 if (xmlXPathIsInf(arg1->floatval) == 1)
4793 ret = 1;
4794 else
4795 ret = 0;
4796 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4797 if (xmlXPathIsInf(arg1->floatval) == -1)
4798 ret = 1;
4799 else
4800 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004801 } else {
4802 ret = (arg1->floatval == arg2->floatval);
4803 }
Owen Taylor3473f882001-02-23 17:55:21 +00004804 break;
4805 case XPATH_USERS:
4806 case XPATH_POINT:
4807 case XPATH_RANGE:
4808 case XPATH_LOCATIONSET:
4809 TODO
4810 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004811 case XPATH_NODESET:
4812 case XPATH_XSLT_TREE:
4813 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004814 }
4815 break;
4816 case XPATH_STRING:
4817 switch (arg2->type) {
4818 case XPATH_UNDEFINED:
4819#ifdef DEBUG_EXPR
4820 xmlGenericError(xmlGenericErrorContext,
4821 "Equal: undefined\n");
4822#endif
4823 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004824 case XPATH_BOOLEAN:
4825 if ((arg1->stringval == NULL) ||
4826 (arg1->stringval[0] == 0)) ret = 0;
4827 else
4828 ret = 1;
4829 ret = (arg2->boolval == ret);
4830 break;
4831 case XPATH_STRING:
4832 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4833 break;
4834 case XPATH_NUMBER:
4835 valuePush(ctxt, arg1);
4836 xmlXPathNumberFunction(ctxt, 1);
4837 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004838 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004839 if (xmlXPathIsNaN(arg1->floatval) ||
4840 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004841 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004842 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4843 if (xmlXPathIsInf(arg2->floatval) == 1)
4844 ret = 1;
4845 else
4846 ret = 0;
4847 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4848 if (xmlXPathIsInf(arg2->floatval) == -1)
4849 ret = 1;
4850 else
4851 ret = 0;
4852 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4853 if (xmlXPathIsInf(arg1->floatval) == 1)
4854 ret = 1;
4855 else
4856 ret = 0;
4857 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4858 if (xmlXPathIsInf(arg1->floatval) == -1)
4859 ret = 1;
4860 else
4861 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004862 } else {
4863 ret = (arg1->floatval == arg2->floatval);
4864 }
Owen Taylor3473f882001-02-23 17:55:21 +00004865 break;
4866 case XPATH_USERS:
4867 case XPATH_POINT:
4868 case XPATH_RANGE:
4869 case XPATH_LOCATIONSET:
4870 TODO
4871 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004872 case XPATH_NODESET:
4873 case XPATH_XSLT_TREE:
4874 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004875 }
4876 break;
4877 case XPATH_USERS:
4878 case XPATH_POINT:
4879 case XPATH_RANGE:
4880 case XPATH_LOCATIONSET:
4881 TODO
4882 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004883 case XPATH_NODESET:
4884 case XPATH_XSLT_TREE:
4885 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004886 }
4887 xmlXPathFreeObject(arg1);
4888 xmlXPathFreeObject(arg2);
4889 return(ret);
4890}
4891
William M. Brack0c022ad2002-07-12 00:56:01 +00004892/**
4893 * xmlXPathEqualValues:
4894 * @ctxt: the XPath Parser context
4895 *
4896 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4897 *
4898 * Returns 0 or 1 depending on the results of the test.
4899 */
4900int
4901xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4902 xmlXPathObjectPtr arg1, arg2, argtmp;
4903 int ret = 0;
4904
Daniel Veillard6128c012004-11-08 17:16:15 +00004905 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00004906 arg2 = valuePop(ctxt);
4907 arg1 = valuePop(ctxt);
4908 if ((arg1 == NULL) || (arg2 == NULL)) {
4909 if (arg1 != NULL)
4910 xmlXPathFreeObject(arg1);
4911 else
4912 xmlXPathFreeObject(arg2);
4913 XP_ERROR0(XPATH_INVALID_OPERAND);
4914 }
4915
4916 if (arg1 == arg2) {
4917#ifdef DEBUG_EXPR
4918 xmlGenericError(xmlGenericErrorContext,
4919 "Equal: by pointer\n");
4920#endif
4921 return(1);
4922 }
4923
4924 /*
4925 *If either argument is a nodeset, it's a 'special case'
4926 */
4927 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4928 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4929 /*
4930 *Hack it to assure arg1 is the nodeset
4931 */
4932 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4933 argtmp = arg2;
4934 arg2 = arg1;
4935 arg1 = argtmp;
4936 }
4937 switch (arg2->type) {
4938 case XPATH_UNDEFINED:
4939#ifdef DEBUG_EXPR
4940 xmlGenericError(xmlGenericErrorContext,
4941 "Equal: undefined\n");
4942#endif
4943 break;
4944 case XPATH_NODESET:
4945 case XPATH_XSLT_TREE:
4946 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4947 break;
4948 case XPATH_BOOLEAN:
4949 if ((arg1->nodesetval == NULL) ||
4950 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4951 else
4952 ret = 1;
4953 ret = (ret == arg2->boolval);
4954 break;
4955 case XPATH_NUMBER:
4956 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4957 break;
4958 case XPATH_STRING:
4959 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4960 break;
4961 case XPATH_USERS:
4962 case XPATH_POINT:
4963 case XPATH_RANGE:
4964 case XPATH_LOCATIONSET:
4965 TODO
4966 break;
4967 }
4968 xmlXPathFreeObject(arg1);
4969 xmlXPathFreeObject(arg2);
4970 return(ret);
4971 }
4972
4973 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4974}
4975
4976/**
4977 * xmlXPathNotEqualValues:
4978 * @ctxt: the XPath Parser context
4979 *
4980 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4981 *
4982 * Returns 0 or 1 depending on the results of the test.
4983 */
4984int
4985xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4986 xmlXPathObjectPtr arg1, arg2, argtmp;
4987 int ret = 0;
4988
Daniel Veillard6128c012004-11-08 17:16:15 +00004989 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00004990 arg2 = valuePop(ctxt);
4991 arg1 = valuePop(ctxt);
4992 if ((arg1 == NULL) || (arg2 == NULL)) {
4993 if (arg1 != NULL)
4994 xmlXPathFreeObject(arg1);
4995 else
4996 xmlXPathFreeObject(arg2);
4997 XP_ERROR0(XPATH_INVALID_OPERAND);
4998 }
4999
5000 if (arg1 == arg2) {
5001#ifdef DEBUG_EXPR
5002 xmlGenericError(xmlGenericErrorContext,
5003 "NotEqual: by pointer\n");
5004#endif
5005 return(0);
5006 }
5007
5008 /*
5009 *If either argument is a nodeset, it's a 'special case'
5010 */
5011 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5012 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5013 /*
5014 *Hack it to assure arg1 is the nodeset
5015 */
5016 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5017 argtmp = arg2;
5018 arg2 = arg1;
5019 arg1 = argtmp;
5020 }
5021 switch (arg2->type) {
5022 case XPATH_UNDEFINED:
5023#ifdef DEBUG_EXPR
5024 xmlGenericError(xmlGenericErrorContext,
5025 "NotEqual: undefined\n");
5026#endif
5027 break;
5028 case XPATH_NODESET:
5029 case XPATH_XSLT_TREE:
5030 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
5031 break;
5032 case XPATH_BOOLEAN:
5033 if ((arg1->nodesetval == NULL) ||
5034 (arg1->nodesetval->nodeNr == 0)) ret = 0;
5035 else
5036 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00005037 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00005038 break;
5039 case XPATH_NUMBER:
5040 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5041 break;
5042 case XPATH_STRING:
5043 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
5044 break;
5045 case XPATH_USERS:
5046 case XPATH_POINT:
5047 case XPATH_RANGE:
5048 case XPATH_LOCATIONSET:
5049 TODO
5050 break;
5051 }
5052 xmlXPathFreeObject(arg1);
5053 xmlXPathFreeObject(arg2);
5054 return(ret);
5055 }
5056
5057 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5058}
Owen Taylor3473f882001-02-23 17:55:21 +00005059
5060/**
5061 * xmlXPathCompareValues:
5062 * @ctxt: the XPath Parser context
5063 * @inf: less than (1) or greater than (0)
5064 * @strict: is the comparison strict
5065 *
5066 * Implement the compare operation on XPath objects:
5067 * @arg1 < @arg2 (1, 1, ...
5068 * @arg1 <= @arg2 (1, 0, ...
5069 * @arg1 > @arg2 (0, 1, ...
5070 * @arg1 >= @arg2 (0, 0, ...
5071 *
5072 * When neither object to be compared is a node-set and the operator is
5073 * <=, <, >=, >, then the objects are compared by converted both objects
5074 * to numbers and comparing the numbers according to IEEE 754. The <
5075 * comparison will be true if and only if the first number is less than the
5076 * second number. The <= comparison will be true if and only if the first
5077 * number is less than or equal to the second number. The > comparison
5078 * will be true if and only if the first number is greater than the second
5079 * number. The >= comparison will be true if and only if the first number
5080 * is greater than or equal to the second number.
5081 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005082 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005083 */
5084int
5085xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005086 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005087 xmlXPathObjectPtr arg1, arg2;
5088
Daniel Veillard6128c012004-11-08 17:16:15 +00005089 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005090 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005091 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005092 if ((arg1 == NULL) || (arg2 == NULL)) {
5093 if (arg1 != NULL)
5094 xmlXPathFreeObject(arg1);
5095 else
5096 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005097 XP_ERROR0(XPATH_INVALID_OPERAND);
5098 }
5099
William M. Brack0c022ad2002-07-12 00:56:01 +00005100 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5101 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5102 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5103 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005104 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005105 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005106 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005107 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5108 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005109 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005110 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5111 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005112 }
5113 }
5114 return(ret);
5115 }
5116
5117 if (arg1->type != XPATH_NUMBER) {
5118 valuePush(ctxt, arg1);
5119 xmlXPathNumberFunction(ctxt, 1);
5120 arg1 = valuePop(ctxt);
5121 }
5122 if (arg1->type != XPATH_NUMBER) {
5123 xmlXPathFreeObject(arg1);
5124 xmlXPathFreeObject(arg2);
5125 XP_ERROR0(XPATH_INVALID_OPERAND);
5126 }
5127 if (arg2->type != XPATH_NUMBER) {
5128 valuePush(ctxt, arg2);
5129 xmlXPathNumberFunction(ctxt, 1);
5130 arg2 = valuePop(ctxt);
5131 }
5132 if (arg2->type != XPATH_NUMBER) {
5133 xmlXPathFreeObject(arg1);
5134 xmlXPathFreeObject(arg2);
5135 XP_ERROR0(XPATH_INVALID_OPERAND);
5136 }
5137 /*
5138 * Add tests for infinity and nan
5139 * => feedback on 3.4 for Inf and NaN
5140 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005141 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005142 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005143 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005144 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005145 arg1i=xmlXPathIsInf(arg1->floatval);
5146 arg2i=xmlXPathIsInf(arg2->floatval);
5147 if (inf && strict) {
5148 if ((arg1i == -1 && arg2i != -1) ||
5149 (arg2i == 1 && arg1i != 1)) {
5150 ret = 1;
5151 } else if (arg1i == 0 && arg2i == 0) {
5152 ret = (arg1->floatval < arg2->floatval);
5153 } else {
5154 ret = 0;
5155 }
5156 }
5157 else if (inf && !strict) {
5158 if (arg1i == -1 || arg2i == 1) {
5159 ret = 1;
5160 } else if (arg1i == 0 && arg2i == 0) {
5161 ret = (arg1->floatval <= arg2->floatval);
5162 } else {
5163 ret = 0;
5164 }
5165 }
5166 else if (!inf && strict) {
5167 if ((arg1i == 1 && arg2i != 1) ||
5168 (arg2i == -1 && arg1i != -1)) {
5169 ret = 1;
5170 } else if (arg1i == 0 && arg2i == 0) {
5171 ret = (arg1->floatval > arg2->floatval);
5172 } else {
5173 ret = 0;
5174 }
5175 }
5176 else if (!inf && !strict) {
5177 if (arg1i == 1 || arg2i == -1) {
5178 ret = 1;
5179 } else if (arg1i == 0 && arg2i == 0) {
5180 ret = (arg1->floatval >= arg2->floatval);
5181 } else {
5182 ret = 0;
5183 }
5184 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005185 }
Owen Taylor3473f882001-02-23 17:55:21 +00005186 xmlXPathFreeObject(arg1);
5187 xmlXPathFreeObject(arg2);
5188 return(ret);
5189}
5190
5191/**
5192 * xmlXPathValueFlipSign:
5193 * @ctxt: the XPath Parser context
5194 *
5195 * Implement the unary - operation on an XPath object
5196 * The numeric operators convert their operands to numbers as if
5197 * by calling the number function.
5198 */
5199void
5200xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005201 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005202 CAST_TO_NUMBER;
5203 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005204 if (xmlXPathIsNaN(ctxt->value->floatval))
5205 ctxt->value->floatval=xmlXPathNAN;
5206 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5207 ctxt->value->floatval=xmlXPathNINF;
5208 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5209 ctxt->value->floatval=xmlXPathPINF;
5210 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005211 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5212 ctxt->value->floatval = xmlXPathNZERO;
5213 else
5214 ctxt->value->floatval = 0;
5215 }
5216 else
5217 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005218}
5219
5220/**
5221 * xmlXPathAddValues:
5222 * @ctxt: the XPath Parser context
5223 *
5224 * Implement the add operation on XPath objects:
5225 * The numeric operators convert their operands to numbers as if
5226 * by calling the number function.
5227 */
5228void
5229xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5230 xmlXPathObjectPtr arg;
5231 double val;
5232
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005233 arg = valuePop(ctxt);
5234 if (arg == NULL)
5235 XP_ERROR(XPATH_INVALID_OPERAND);
5236 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005237 xmlXPathFreeObject(arg);
5238
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005239 CAST_TO_NUMBER;
5240 CHECK_TYPE(XPATH_NUMBER);
5241 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005242}
5243
5244/**
5245 * xmlXPathSubValues:
5246 * @ctxt: the XPath Parser context
5247 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005248 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005249 * The numeric operators convert their operands to numbers as if
5250 * by calling the number function.
5251 */
5252void
5253xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5254 xmlXPathObjectPtr arg;
5255 double val;
5256
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005257 arg = valuePop(ctxt);
5258 if (arg == NULL)
5259 XP_ERROR(XPATH_INVALID_OPERAND);
5260 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005261 xmlXPathFreeObject(arg);
5262
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005263 CAST_TO_NUMBER;
5264 CHECK_TYPE(XPATH_NUMBER);
5265 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005266}
5267
5268/**
5269 * xmlXPathMultValues:
5270 * @ctxt: the XPath Parser context
5271 *
5272 * Implement the multiply operation on XPath objects:
5273 * The numeric operators convert their operands to numbers as if
5274 * by calling the number function.
5275 */
5276void
5277xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5278 xmlXPathObjectPtr arg;
5279 double val;
5280
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005281 arg = valuePop(ctxt);
5282 if (arg == NULL)
5283 XP_ERROR(XPATH_INVALID_OPERAND);
5284 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005285 xmlXPathFreeObject(arg);
5286
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005287 CAST_TO_NUMBER;
5288 CHECK_TYPE(XPATH_NUMBER);
5289 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005290}
5291
5292/**
5293 * xmlXPathDivValues:
5294 * @ctxt: the XPath Parser context
5295 *
5296 * Implement the div operation on XPath objects @arg1 / @arg2:
5297 * The numeric operators convert their operands to numbers as if
5298 * by calling the number function.
5299 */
5300void
5301xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5302 xmlXPathObjectPtr arg;
5303 double val;
5304
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005305 arg = valuePop(ctxt);
5306 if (arg == NULL)
5307 XP_ERROR(XPATH_INVALID_OPERAND);
5308 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005309 xmlXPathFreeObject(arg);
5310
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005311 CAST_TO_NUMBER;
5312 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005313 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5314 ctxt->value->floatval = xmlXPathNAN;
5315 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005316 if (ctxt->value->floatval == 0)
5317 ctxt->value->floatval = xmlXPathNAN;
5318 else if (ctxt->value->floatval > 0)
5319 ctxt->value->floatval = xmlXPathNINF;
5320 else if (ctxt->value->floatval < 0)
5321 ctxt->value->floatval = xmlXPathPINF;
5322 }
5323 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005324 if (ctxt->value->floatval == 0)
5325 ctxt->value->floatval = xmlXPathNAN;
5326 else if (ctxt->value->floatval > 0)
5327 ctxt->value->floatval = xmlXPathPINF;
5328 else if (ctxt->value->floatval < 0)
5329 ctxt->value->floatval = xmlXPathNINF;
5330 } else
5331 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005332}
5333
5334/**
5335 * xmlXPathModValues:
5336 * @ctxt: the XPath Parser context
5337 *
5338 * Implement the mod operation on XPath objects: @arg1 / @arg2
5339 * The numeric operators convert their operands to numbers as if
5340 * by calling the number function.
5341 */
5342void
5343xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5344 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005345 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005346
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005347 arg = valuePop(ctxt);
5348 if (arg == NULL)
5349 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005350 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005351 xmlXPathFreeObject(arg);
5352
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005353 CAST_TO_NUMBER;
5354 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005355 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005356 if (arg2 == 0)
5357 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005358 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005359 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005360 }
Owen Taylor3473f882001-02-23 17:55:21 +00005361}
5362
5363/************************************************************************
5364 * *
5365 * The traversal functions *
5366 * *
5367 ************************************************************************/
5368
Owen Taylor3473f882001-02-23 17:55:21 +00005369/*
5370 * A traversal function enumerates nodes along an axis.
5371 * Initially it must be called with NULL, and it indicates
5372 * termination on the axis by returning NULL.
5373 */
5374typedef xmlNodePtr (*xmlXPathTraversalFunction)
5375 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5376
5377/**
5378 * xmlXPathNextSelf:
5379 * @ctxt: the XPath Parser context
5380 * @cur: the current node in the traversal
5381 *
5382 * Traversal function for the "self" direction
5383 * The self axis contains just the context node itself
5384 *
5385 * Returns the next element following that axis
5386 */
5387xmlNodePtr
5388xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005389 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005390 if (cur == NULL)
5391 return(ctxt->context->node);
5392 return(NULL);
5393}
5394
5395/**
5396 * xmlXPathNextChild:
5397 * @ctxt: the XPath Parser context
5398 * @cur: the current node in the traversal
5399 *
5400 * Traversal function for the "child" direction
5401 * The child axis contains the children of the context node in document order.
5402 *
5403 * Returns the next element following that axis
5404 */
5405xmlNodePtr
5406xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005407 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005408 if (cur == NULL) {
5409 if (ctxt->context->node == NULL) return(NULL);
5410 switch (ctxt->context->node->type) {
5411 case XML_ELEMENT_NODE:
5412 case XML_TEXT_NODE:
5413 case XML_CDATA_SECTION_NODE:
5414 case XML_ENTITY_REF_NODE:
5415 case XML_ENTITY_NODE:
5416 case XML_PI_NODE:
5417 case XML_COMMENT_NODE:
5418 case XML_NOTATION_NODE:
5419 case XML_DTD_NODE:
5420 return(ctxt->context->node->children);
5421 case XML_DOCUMENT_NODE:
5422 case XML_DOCUMENT_TYPE_NODE:
5423 case XML_DOCUMENT_FRAG_NODE:
5424 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005425#ifdef LIBXML_DOCB_ENABLED
5426 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005427#endif
5428 return(((xmlDocPtr) ctxt->context->node)->children);
5429 case XML_ELEMENT_DECL:
5430 case XML_ATTRIBUTE_DECL:
5431 case XML_ENTITY_DECL:
5432 case XML_ATTRIBUTE_NODE:
5433 case XML_NAMESPACE_DECL:
5434 case XML_XINCLUDE_START:
5435 case XML_XINCLUDE_END:
5436 return(NULL);
5437 }
5438 return(NULL);
5439 }
5440 if ((cur->type == XML_DOCUMENT_NODE) ||
5441 (cur->type == XML_HTML_DOCUMENT_NODE))
5442 return(NULL);
5443 return(cur->next);
5444}
5445
5446/**
5447 * xmlXPathNextDescendant:
5448 * @ctxt: the XPath Parser context
5449 * @cur: the current node in the traversal
5450 *
5451 * Traversal function for the "descendant" direction
5452 * the descendant axis contains the descendants of the context node in document
5453 * order; a descendant is a child or a child of a child and so on.
5454 *
5455 * Returns the next element following that axis
5456 */
5457xmlNodePtr
5458xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005459 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005460 if (cur == NULL) {
5461 if (ctxt->context->node == NULL)
5462 return(NULL);
5463 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5464 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5465 return(NULL);
5466
5467 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5468 return(ctxt->context->doc->children);
5469 return(ctxt->context->node->children);
5470 }
5471
Daniel Veillard567e1b42001-08-01 15:53:47 +00005472 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005473 /*
5474 * Do not descend on entities declarations
5475 */
5476 if (cur->children->type != XML_ENTITY_DECL) {
5477 cur = cur->children;
5478 /*
5479 * Skip DTDs
5480 */
5481 if (cur->type != XML_DTD_NODE)
5482 return(cur);
5483 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005484 }
5485
5486 if (cur == ctxt->context->node) return(NULL);
5487
Daniel Veillard68e9e742002-11-16 15:35:11 +00005488 while (cur->next != NULL) {
5489 cur = cur->next;
5490 if ((cur->type != XML_ENTITY_DECL) &&
5491 (cur->type != XML_DTD_NODE))
5492 return(cur);
5493 }
Owen Taylor3473f882001-02-23 17:55:21 +00005494
5495 do {
5496 cur = cur->parent;
5497 if (cur == NULL) return(NULL);
5498 if (cur == ctxt->context->node) return(NULL);
5499 if (cur->next != NULL) {
5500 cur = cur->next;
5501 return(cur);
5502 }
5503 } while (cur != NULL);
5504 return(cur);
5505}
5506
5507/**
5508 * xmlXPathNextDescendantOrSelf:
5509 * @ctxt: the XPath Parser context
5510 * @cur: the current node in the traversal
5511 *
5512 * Traversal function for the "descendant-or-self" direction
5513 * the descendant-or-self axis contains the context node and the descendants
5514 * of the context node in document order; thus the context node is the first
5515 * node on the axis, and the first child of the context node is the second node
5516 * on the axis
5517 *
5518 * Returns the next element following that axis
5519 */
5520xmlNodePtr
5521xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005522 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005523 if (cur == NULL) {
5524 if (ctxt->context->node == NULL)
5525 return(NULL);
5526 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5527 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5528 return(NULL);
5529 return(ctxt->context->node);
5530 }
5531
5532 return(xmlXPathNextDescendant(ctxt, cur));
5533}
5534
5535/**
5536 * xmlXPathNextParent:
5537 * @ctxt: the XPath Parser context
5538 * @cur: the current node in the traversal
5539 *
5540 * Traversal function for the "parent" direction
5541 * The parent axis contains the parent of the context node, if there is one.
5542 *
5543 * Returns the next element following that axis
5544 */
5545xmlNodePtr
5546xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005547 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005548 /*
5549 * the parent of an attribute or namespace node is the element
5550 * to which the attribute or namespace node is attached
5551 * Namespace handling !!!
5552 */
5553 if (cur == NULL) {
5554 if (ctxt->context->node == NULL) return(NULL);
5555 switch (ctxt->context->node->type) {
5556 case XML_ELEMENT_NODE:
5557 case XML_TEXT_NODE:
5558 case XML_CDATA_SECTION_NODE:
5559 case XML_ENTITY_REF_NODE:
5560 case XML_ENTITY_NODE:
5561 case XML_PI_NODE:
5562 case XML_COMMENT_NODE:
5563 case XML_NOTATION_NODE:
5564 case XML_DTD_NODE:
5565 case XML_ELEMENT_DECL:
5566 case XML_ATTRIBUTE_DECL:
5567 case XML_XINCLUDE_START:
5568 case XML_XINCLUDE_END:
5569 case XML_ENTITY_DECL:
5570 if (ctxt->context->node->parent == NULL)
5571 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005572 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005573 ((ctxt->context->node->parent->name[0] == ' ') ||
5574 (xmlStrEqual(ctxt->context->node->parent->name,
5575 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005576 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005577 return(ctxt->context->node->parent);
5578 case XML_ATTRIBUTE_NODE: {
5579 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5580
5581 return(att->parent);
5582 }
5583 case XML_DOCUMENT_NODE:
5584 case XML_DOCUMENT_TYPE_NODE:
5585 case XML_DOCUMENT_FRAG_NODE:
5586 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005587#ifdef LIBXML_DOCB_ENABLED
5588 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005589#endif
5590 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005591 case XML_NAMESPACE_DECL: {
5592 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5593
5594 if ((ns->next != NULL) &&
5595 (ns->next->type != XML_NAMESPACE_DECL))
5596 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005597 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005598 }
Owen Taylor3473f882001-02-23 17:55:21 +00005599 }
5600 }
5601 return(NULL);
5602}
5603
5604/**
5605 * xmlXPathNextAncestor:
5606 * @ctxt: the XPath Parser context
5607 * @cur: the current node in the traversal
5608 *
5609 * Traversal function for the "ancestor" direction
5610 * the ancestor axis contains the ancestors of the context node; the ancestors
5611 * of the context node consist of the parent of context node and the parent's
5612 * parent and so on; the nodes are ordered in reverse document order; thus the
5613 * parent is the first node on the axis, and the parent's parent is the second
5614 * node on the axis
5615 *
5616 * Returns the next element following that axis
5617 */
5618xmlNodePtr
5619xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005620 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005621 /*
5622 * the parent of an attribute or namespace node is the element
5623 * to which the attribute or namespace node is attached
5624 * !!!!!!!!!!!!!
5625 */
5626 if (cur == NULL) {
5627 if (ctxt->context->node == NULL) return(NULL);
5628 switch (ctxt->context->node->type) {
5629 case XML_ELEMENT_NODE:
5630 case XML_TEXT_NODE:
5631 case XML_CDATA_SECTION_NODE:
5632 case XML_ENTITY_REF_NODE:
5633 case XML_ENTITY_NODE:
5634 case XML_PI_NODE:
5635 case XML_COMMENT_NODE:
5636 case XML_DTD_NODE:
5637 case XML_ELEMENT_DECL:
5638 case XML_ATTRIBUTE_DECL:
5639 case XML_ENTITY_DECL:
5640 case XML_NOTATION_NODE:
5641 case XML_XINCLUDE_START:
5642 case XML_XINCLUDE_END:
5643 if (ctxt->context->node->parent == NULL)
5644 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005645 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005646 ((ctxt->context->node->parent->name[0] == ' ') ||
5647 (xmlStrEqual(ctxt->context->node->parent->name,
5648 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005649 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005650 return(ctxt->context->node->parent);
5651 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005652 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005653
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005654 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005655 }
5656 case XML_DOCUMENT_NODE:
5657 case XML_DOCUMENT_TYPE_NODE:
5658 case XML_DOCUMENT_FRAG_NODE:
5659 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005660#ifdef LIBXML_DOCB_ENABLED
5661 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005662#endif
5663 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005664 case XML_NAMESPACE_DECL: {
5665 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5666
5667 if ((ns->next != NULL) &&
5668 (ns->next->type != XML_NAMESPACE_DECL))
5669 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005670 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005671 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005672 }
Owen Taylor3473f882001-02-23 17:55:21 +00005673 }
5674 return(NULL);
5675 }
5676 if (cur == ctxt->context->doc->children)
5677 return((xmlNodePtr) ctxt->context->doc);
5678 if (cur == (xmlNodePtr) ctxt->context->doc)
5679 return(NULL);
5680 switch (cur->type) {
5681 case XML_ELEMENT_NODE:
5682 case XML_TEXT_NODE:
5683 case XML_CDATA_SECTION_NODE:
5684 case XML_ENTITY_REF_NODE:
5685 case XML_ENTITY_NODE:
5686 case XML_PI_NODE:
5687 case XML_COMMENT_NODE:
5688 case XML_NOTATION_NODE:
5689 case XML_DTD_NODE:
5690 case XML_ELEMENT_DECL:
5691 case XML_ATTRIBUTE_DECL:
5692 case XML_ENTITY_DECL:
5693 case XML_XINCLUDE_START:
5694 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005695 if (cur->parent == NULL)
5696 return(NULL);
5697 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005698 ((cur->parent->name[0] == ' ') ||
5699 (xmlStrEqual(cur->parent->name,
5700 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005701 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005702 return(cur->parent);
5703 case XML_ATTRIBUTE_NODE: {
5704 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5705
5706 return(att->parent);
5707 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005708 case XML_NAMESPACE_DECL: {
5709 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5710
5711 if ((ns->next != NULL) &&
5712 (ns->next->type != XML_NAMESPACE_DECL))
5713 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005714 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005715 return(NULL);
5716 }
Owen Taylor3473f882001-02-23 17:55:21 +00005717 case XML_DOCUMENT_NODE:
5718 case XML_DOCUMENT_TYPE_NODE:
5719 case XML_DOCUMENT_FRAG_NODE:
5720 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005721#ifdef LIBXML_DOCB_ENABLED
5722 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005723#endif
5724 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005725 }
5726 return(NULL);
5727}
5728
5729/**
5730 * xmlXPathNextAncestorOrSelf:
5731 * @ctxt: the XPath Parser context
5732 * @cur: the current node in the traversal
5733 *
5734 * Traversal function for the "ancestor-or-self" direction
5735 * he ancestor-or-self axis contains the context node and ancestors of
5736 * the context node in reverse document order; thus the context node is
5737 * the first node on the axis, and the context node's parent the second;
5738 * parent here is defined the same as with the parent axis.
5739 *
5740 * Returns the next element following that axis
5741 */
5742xmlNodePtr
5743xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005744 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005745 if (cur == NULL)
5746 return(ctxt->context->node);
5747 return(xmlXPathNextAncestor(ctxt, cur));
5748}
5749
5750/**
5751 * xmlXPathNextFollowingSibling:
5752 * @ctxt: the XPath Parser context
5753 * @cur: the current node in the traversal
5754 *
5755 * Traversal function for the "following-sibling" direction
5756 * The following-sibling axis contains the following siblings of the context
5757 * node in document order.
5758 *
5759 * Returns the next element following that axis
5760 */
5761xmlNodePtr
5762xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005763 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005764 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5765 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5766 return(NULL);
5767 if (cur == (xmlNodePtr) ctxt->context->doc)
5768 return(NULL);
5769 if (cur == NULL)
5770 return(ctxt->context->node->next);
5771 return(cur->next);
5772}
5773
5774/**
5775 * xmlXPathNextPrecedingSibling:
5776 * @ctxt: the XPath Parser context
5777 * @cur: the current node in the traversal
5778 *
5779 * Traversal function for the "preceding-sibling" direction
5780 * The preceding-sibling axis contains the preceding siblings of the context
5781 * node in reverse document order; the first preceding sibling is first on the
5782 * axis; the sibling preceding that node is the second on the axis and so on.
5783 *
5784 * Returns the next element following that axis
5785 */
5786xmlNodePtr
5787xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005788 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005789 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5790 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5791 return(NULL);
5792 if (cur == (xmlNodePtr) ctxt->context->doc)
5793 return(NULL);
5794 if (cur == NULL)
5795 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005796 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5797 cur = cur->prev;
5798 if (cur == NULL)
5799 return(ctxt->context->node->prev);
5800 }
Owen Taylor3473f882001-02-23 17:55:21 +00005801 return(cur->prev);
5802}
5803
5804/**
5805 * xmlXPathNextFollowing:
5806 * @ctxt: the XPath Parser context
5807 * @cur: the current node in the traversal
5808 *
5809 * Traversal function for the "following" direction
5810 * The following axis contains all nodes in the same document as the context
5811 * node that are after the context node in document order, excluding any
5812 * descendants and excluding attribute nodes and namespace nodes; the nodes
5813 * are ordered in document order
5814 *
5815 * Returns the next element following that axis
5816 */
5817xmlNodePtr
5818xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005819 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005820 if (cur != NULL && cur->children != NULL)
5821 return cur->children ;
5822 if (cur == NULL) cur = ctxt->context->node;
5823 if (cur == NULL) return(NULL) ; /* ERROR */
5824 if (cur->next != NULL) return(cur->next) ;
5825 do {
5826 cur = cur->parent;
5827 if (cur == NULL) return(NULL);
5828 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5829 if (cur->next != NULL) return(cur->next);
5830 } while (cur != NULL);
5831 return(cur);
5832}
5833
5834/*
5835 * xmlXPathIsAncestor:
5836 * @ancestor: the ancestor node
5837 * @node: the current node
5838 *
5839 * Check that @ancestor is a @node's ancestor
5840 *
5841 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5842 */
5843static int
5844xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5845 if ((ancestor == NULL) || (node == NULL)) return(0);
5846 /* nodes need to be in the same document */
5847 if (ancestor->doc != node->doc) return(0);
5848 /* avoid searching if ancestor or node is the root node */
5849 if (ancestor == (xmlNodePtr) node->doc) return(1);
5850 if (node == (xmlNodePtr) ancestor->doc) return(0);
5851 while (node->parent != NULL) {
5852 if (node->parent == ancestor)
5853 return(1);
5854 node = node->parent;
5855 }
5856 return(0);
5857}
5858
5859/**
5860 * xmlXPathNextPreceding:
5861 * @ctxt: the XPath Parser context
5862 * @cur: the current node in the traversal
5863 *
5864 * Traversal function for the "preceding" direction
5865 * the preceding axis contains all nodes in the same document as the context
5866 * node that are before the context node in document order, excluding any
5867 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5868 * ordered in reverse document order
5869 *
5870 * Returns the next element following that axis
5871 */
5872xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005873xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5874{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005875 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005876 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005877 cur = ctxt->context->node;
5878 if (cur == NULL)
5879 return (NULL);
5880 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5881 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005882 do {
5883 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005884 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5885 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005886 }
5887
5888 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005889 if (cur == NULL)
5890 return (NULL);
5891 if (cur == ctxt->context->doc->children)
5892 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005893 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005894 return (cur);
5895}
5896
5897/**
5898 * xmlXPathNextPrecedingInternal:
5899 * @ctxt: the XPath Parser context
5900 * @cur: the current node in the traversal
5901 *
5902 * Traversal function for the "preceding" direction
5903 * the preceding axis contains all nodes in the same document as the context
5904 * node that are before the context node in document order, excluding any
5905 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5906 * ordered in reverse document order
5907 * This is a faster implementation but internal only since it requires a
5908 * state kept in the parser context: ctxt->ancestor.
5909 *
5910 * Returns the next element following that axis
5911 */
5912static xmlNodePtr
5913xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5914 xmlNodePtr cur)
5915{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005916 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005917 if (cur == NULL) {
5918 cur = ctxt->context->node;
5919 if (cur == NULL)
5920 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005921 if (cur->type == XML_NAMESPACE_DECL)
5922 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005923 ctxt->ancestor = cur->parent;
5924 }
5925 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5926 cur = cur->prev;
5927 while (cur->prev == NULL) {
5928 cur = cur->parent;
5929 if (cur == NULL)
5930 return (NULL);
5931 if (cur == ctxt->context->doc->children)
5932 return (NULL);
5933 if (cur != ctxt->ancestor)
5934 return (cur);
5935 ctxt->ancestor = cur->parent;
5936 }
5937 cur = cur->prev;
5938 while (cur->last != NULL)
5939 cur = cur->last;
5940 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005941}
5942
5943/**
5944 * xmlXPathNextNamespace:
5945 * @ctxt: the XPath Parser context
5946 * @cur: the current attribute in the traversal
5947 *
5948 * Traversal function for the "namespace" direction
5949 * the namespace axis contains the namespace nodes of the context node;
5950 * the order of nodes on this axis is implementation-defined; the axis will
5951 * be empty unless the context node is an element
5952 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005953 * We keep the XML namespace node at the end of the list.
5954 *
Owen Taylor3473f882001-02-23 17:55:21 +00005955 * Returns the next element following that axis
5956 */
5957xmlNodePtr
5958xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005959 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005960 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005961 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005962 if (ctxt->context->tmpNsList != NULL)
5963 xmlFree(ctxt->context->tmpNsList);
5964 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005965 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005966 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005967 if (ctxt->context->tmpNsList != NULL) {
5968 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5969 ctxt->context->tmpNsNr++;
5970 }
5971 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005972 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005973 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005974 if (ctxt->context->tmpNsNr > 0) {
5975 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5976 } else {
5977 if (ctxt->context->tmpNsList != NULL)
5978 xmlFree(ctxt->context->tmpNsList);
5979 ctxt->context->tmpNsList = NULL;
5980 return(NULL);
5981 }
Owen Taylor3473f882001-02-23 17:55:21 +00005982}
5983
5984/**
5985 * xmlXPathNextAttribute:
5986 * @ctxt: the XPath Parser context
5987 * @cur: the current attribute in the traversal
5988 *
5989 * Traversal function for the "attribute" direction
5990 * TODO: support DTD inherited default attributes
5991 *
5992 * Returns the next element following that axis
5993 */
5994xmlNodePtr
5995xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005996 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00005997 if (ctxt->context->node == NULL)
5998 return(NULL);
5999 if (ctxt->context->node->type != XML_ELEMENT_NODE)
6000 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006001 if (cur == NULL) {
6002 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6003 return(NULL);
6004 return((xmlNodePtr)ctxt->context->node->properties);
6005 }
6006 return((xmlNodePtr)cur->next);
6007}
6008
6009/************************************************************************
6010 * *
6011 * NodeTest Functions *
6012 * *
6013 ************************************************************************/
6014
Owen Taylor3473f882001-02-23 17:55:21 +00006015#define IS_FUNCTION 200
6016
Owen Taylor3473f882001-02-23 17:55:21 +00006017
6018/************************************************************************
6019 * *
6020 * Implicit tree core function library *
6021 * *
6022 ************************************************************************/
6023
6024/**
6025 * xmlXPathRoot:
6026 * @ctxt: the XPath Parser context
6027 *
6028 * Initialize the context to the root of the document
6029 */
6030void
6031xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006032 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006033 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
6034 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6035}
6036
6037/************************************************************************
6038 * *
6039 * The explicit core function library *
6040 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
6041 * *
6042 ************************************************************************/
6043
6044
6045/**
6046 * xmlXPathLastFunction:
6047 * @ctxt: the XPath Parser context
6048 * @nargs: the number of arguments
6049 *
6050 * Implement the last() XPath function
6051 * number last()
6052 * The last function returns the number of nodes in the context node list.
6053 */
6054void
6055xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6056 CHECK_ARITY(0);
6057 if (ctxt->context->contextSize >= 0) {
6058 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
6059#ifdef DEBUG_EXPR
6060 xmlGenericError(xmlGenericErrorContext,
6061 "last() : %d\n", ctxt->context->contextSize);
6062#endif
6063 } else {
6064 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6065 }
6066}
6067
6068/**
6069 * xmlXPathPositionFunction:
6070 * @ctxt: the XPath Parser context
6071 * @nargs: the number of arguments
6072 *
6073 * Implement the position() XPath function
6074 * number position()
6075 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006076 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00006077 * will be equal to last().
6078 */
6079void
6080xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6081 CHECK_ARITY(0);
6082 if (ctxt->context->proximityPosition >= 0) {
6083 valuePush(ctxt,
6084 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6085#ifdef DEBUG_EXPR
6086 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6087 ctxt->context->proximityPosition);
6088#endif
6089 } else {
6090 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6091 }
6092}
6093
6094/**
6095 * xmlXPathCountFunction:
6096 * @ctxt: the XPath Parser context
6097 * @nargs: the number of arguments
6098 *
6099 * Implement the count() XPath function
6100 * number count(node-set)
6101 */
6102void
6103xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6104 xmlXPathObjectPtr cur;
6105
6106 CHECK_ARITY(1);
6107 if ((ctxt->value == NULL) ||
6108 ((ctxt->value->type != XPATH_NODESET) &&
6109 (ctxt->value->type != XPATH_XSLT_TREE)))
6110 XP_ERROR(XPATH_INVALID_TYPE);
6111 cur = valuePop(ctxt);
6112
Daniel Veillard911f49a2001-04-07 15:39:35 +00006113 if ((cur == NULL) || (cur->nodesetval == NULL))
6114 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006115 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006116 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006117 } else {
6118 if ((cur->nodesetval->nodeNr != 1) ||
6119 (cur->nodesetval->nodeTab == NULL)) {
6120 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6121 } else {
6122 xmlNodePtr tmp;
6123 int i = 0;
6124
6125 tmp = cur->nodesetval->nodeTab[0];
6126 if (tmp != NULL) {
6127 tmp = tmp->children;
6128 while (tmp != NULL) {
6129 tmp = tmp->next;
6130 i++;
6131 }
6132 }
6133 valuePush(ctxt, xmlXPathNewFloat((double) i));
6134 }
6135 }
Owen Taylor3473f882001-02-23 17:55:21 +00006136 xmlXPathFreeObject(cur);
6137}
6138
6139/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006140 * xmlXPathGetElementsByIds:
6141 * @doc: the document
6142 * @ids: a whitespace separated list of IDs
6143 *
6144 * Selects elements by their unique ID.
6145 *
6146 * Returns a node-set of selected elements.
6147 */
6148static xmlNodeSetPtr
6149xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6150 xmlNodeSetPtr ret;
6151 const xmlChar *cur = ids;
6152 xmlChar *ID;
6153 xmlAttrPtr attr;
6154 xmlNodePtr elem = NULL;
6155
Daniel Veillard7a985a12003-07-06 17:57:42 +00006156 if (ids == NULL) return(NULL);
6157
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006158 ret = xmlXPathNodeSetCreate(NULL);
6159
William M. Brack76e95df2003-10-18 16:20:14 +00006160 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006161 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006162 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006163 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006164
6165 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006166 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00006167 /*
6168 * We used to check the fact that the value passed
6169 * was an NCName, but this generated much troubles for
6170 * me and Aleksey Sanin, people blatantly violated that
6171 * constaint, like Visa3D spec.
6172 * if (xmlValidateNCName(ID, 1) == 0)
6173 */
6174 attr = xmlGetID(doc, ID);
6175 if (attr != NULL) {
6176 if (attr->type == XML_ATTRIBUTE_NODE)
6177 elem = attr->parent;
6178 else if (attr->type == XML_ELEMENT_NODE)
6179 elem = (xmlNodePtr) attr;
6180 else
6181 elem = NULL;
6182 if (elem != NULL)
6183 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00006184 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006185 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006186 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006187
William M. Brack76e95df2003-10-18 16:20:14 +00006188 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006189 ids = cur;
6190 }
6191 return(ret);
6192}
6193
6194/**
Owen Taylor3473f882001-02-23 17:55:21 +00006195 * xmlXPathIdFunction:
6196 * @ctxt: the XPath Parser context
6197 * @nargs: the number of arguments
6198 *
6199 * Implement the id() XPath function
6200 * node-set id(object)
6201 * The id function selects elements by their unique ID
6202 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6203 * then the result is the union of the result of applying id to the
6204 * string value of each of the nodes in the argument node-set. When the
6205 * argument to id is of any other type, the argument is converted to a
6206 * string as if by a call to the string function; the string is split
6207 * into a whitespace-separated list of tokens (whitespace is any sequence
6208 * of characters matching the production S); the result is a node-set
6209 * containing the elements in the same document as the context node that
6210 * have a unique ID equal to any of the tokens in the list.
6211 */
6212void
6213xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006214 xmlChar *tokens;
6215 xmlNodeSetPtr ret;
6216 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006217
6218 CHECK_ARITY(1);
6219 obj = valuePop(ctxt);
6220 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006221 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006222 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006223 int i;
6224
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006225 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006226
Daniel Veillard911f49a2001-04-07 15:39:35 +00006227 if (obj->nodesetval != NULL) {
6228 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006229 tokens =
6230 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6231 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6232 ret = xmlXPathNodeSetMerge(ret, ns);
6233 xmlXPathFreeNodeSet(ns);
6234 if (tokens != NULL)
6235 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006236 }
Owen Taylor3473f882001-02-23 17:55:21 +00006237 }
6238
6239 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006240 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006241 return;
6242 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006243 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006244
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006245 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6246 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006247
Owen Taylor3473f882001-02-23 17:55:21 +00006248 xmlXPathFreeObject(obj);
6249 return;
6250}
6251
6252/**
6253 * xmlXPathLocalNameFunction:
6254 * @ctxt: the XPath Parser context
6255 * @nargs: the number of arguments
6256 *
6257 * Implement the local-name() XPath function
6258 * string local-name(node-set?)
6259 * The local-name function returns a string containing the local part
6260 * of the name of the node in the argument node-set that is first in
6261 * document order. If the node-set is empty or the first node has no
6262 * name, an empty string is returned. If the argument is omitted it
6263 * defaults to the context node.
6264 */
6265void
6266xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6267 xmlXPathObjectPtr cur;
6268
Daniel Veillarda82b1822004-11-08 16:24:57 +00006269 if (ctxt == NULL) return;
6270
Owen Taylor3473f882001-02-23 17:55:21 +00006271 if (nargs == 0) {
6272 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6273 nargs = 1;
6274 }
6275
6276 CHECK_ARITY(1);
6277 if ((ctxt->value == NULL) ||
6278 ((ctxt->value->type != XPATH_NODESET) &&
6279 (ctxt->value->type != XPATH_XSLT_TREE)))
6280 XP_ERROR(XPATH_INVALID_TYPE);
6281 cur = valuePop(ctxt);
6282
Daniel Veillard911f49a2001-04-07 15:39:35 +00006283 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006284 valuePush(ctxt, xmlXPathNewCString(""));
6285 } else {
6286 int i = 0; /* Should be first in document order !!!!! */
6287 switch (cur->nodesetval->nodeTab[i]->type) {
6288 case XML_ELEMENT_NODE:
6289 case XML_ATTRIBUTE_NODE:
6290 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006291 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6292 valuePush(ctxt, xmlXPathNewCString(""));
6293 else
6294 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006295 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6296 break;
6297 case XML_NAMESPACE_DECL:
6298 valuePush(ctxt, xmlXPathNewString(
6299 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6300 break;
6301 default:
6302 valuePush(ctxt, xmlXPathNewCString(""));
6303 }
6304 }
6305 xmlXPathFreeObject(cur);
6306}
6307
6308/**
6309 * xmlXPathNamespaceURIFunction:
6310 * @ctxt: the XPath Parser context
6311 * @nargs: the number of arguments
6312 *
6313 * Implement the namespace-uri() XPath function
6314 * string namespace-uri(node-set?)
6315 * The namespace-uri function returns a string containing the
6316 * namespace URI of the expanded name of the node in the argument
6317 * node-set that is first in document order. If the node-set is empty,
6318 * the first node has no name, or the expanded name has no namespace
6319 * URI, an empty string is returned. If the argument is omitted it
6320 * defaults to the context node.
6321 */
6322void
6323xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6324 xmlXPathObjectPtr cur;
6325
Daniel Veillarda82b1822004-11-08 16:24:57 +00006326 if (ctxt == NULL) return;
6327
Owen Taylor3473f882001-02-23 17:55:21 +00006328 if (nargs == 0) {
6329 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6330 nargs = 1;
6331 }
6332 CHECK_ARITY(1);
6333 if ((ctxt->value == NULL) ||
6334 ((ctxt->value->type != XPATH_NODESET) &&
6335 (ctxt->value->type != XPATH_XSLT_TREE)))
6336 XP_ERROR(XPATH_INVALID_TYPE);
6337 cur = valuePop(ctxt);
6338
Daniel Veillard911f49a2001-04-07 15:39:35 +00006339 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006340 valuePush(ctxt, xmlXPathNewCString(""));
6341 } else {
6342 int i = 0; /* Should be first in document order !!!!! */
6343 switch (cur->nodesetval->nodeTab[i]->type) {
6344 case XML_ELEMENT_NODE:
6345 case XML_ATTRIBUTE_NODE:
6346 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6347 valuePush(ctxt, xmlXPathNewCString(""));
6348 else
6349 valuePush(ctxt, xmlXPathNewString(
6350 cur->nodesetval->nodeTab[i]->ns->href));
6351 break;
6352 default:
6353 valuePush(ctxt, xmlXPathNewCString(""));
6354 }
6355 }
6356 xmlXPathFreeObject(cur);
6357}
6358
6359/**
6360 * xmlXPathNameFunction:
6361 * @ctxt: the XPath Parser context
6362 * @nargs: the number of arguments
6363 *
6364 * Implement the name() XPath function
6365 * string name(node-set?)
6366 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006367 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006368 * order. The QName must represent the name with respect to the namespace
6369 * declarations in effect on the node whose name is being represented.
6370 * Typically, this will be the form in which the name occurred in the XML
6371 * source. This need not be the case if there are namespace declarations
6372 * in effect on the node that associate multiple prefixes with the same
6373 * namespace. However, an implementation may include information about
6374 * the original prefix in its representation of nodes; in this case, an
6375 * implementation can ensure that the returned string is always the same
6376 * as the QName used in the XML source. If the argument it omitted it
6377 * defaults to the context node.
6378 * Libxml keep the original prefix so the "real qualified name" used is
6379 * returned.
6380 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006381static void
Daniel Veillard04383752001-07-08 14:27:15 +00006382xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6383{
Owen Taylor3473f882001-02-23 17:55:21 +00006384 xmlXPathObjectPtr cur;
6385
6386 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006387 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6388 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006389 }
6390
6391 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006392 if ((ctxt->value == NULL) ||
6393 ((ctxt->value->type != XPATH_NODESET) &&
6394 (ctxt->value->type != XPATH_XSLT_TREE)))
6395 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006396 cur = valuePop(ctxt);
6397
Daniel Veillard911f49a2001-04-07 15:39:35 +00006398 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006399 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006400 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006401 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006402
Daniel Veillard04383752001-07-08 14:27:15 +00006403 switch (cur->nodesetval->nodeTab[i]->type) {
6404 case XML_ELEMENT_NODE:
6405 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006406 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6407 valuePush(ctxt, xmlXPathNewCString(""));
6408 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6409 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006410 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006411 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006412
Daniel Veillard652d8a92003-02-04 19:28:49 +00006413 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006414 xmlChar *fullname;
6415
6416 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6417 cur->nodesetval->nodeTab[i]->ns->prefix,
6418 NULL, 0);
6419 if (fullname == cur->nodesetval->nodeTab[i]->name)
6420 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6421 if (fullname == NULL) {
6422 XP_ERROR(XPATH_MEMORY_ERROR);
6423 }
6424 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006425 }
6426 break;
6427 default:
6428 valuePush(ctxt,
6429 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6430 xmlXPathLocalNameFunction(ctxt, 1);
6431 }
Owen Taylor3473f882001-02-23 17:55:21 +00006432 }
6433 xmlXPathFreeObject(cur);
6434}
6435
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006436
6437/**
Owen Taylor3473f882001-02-23 17:55:21 +00006438 * xmlXPathStringFunction:
6439 * @ctxt: the XPath Parser context
6440 * @nargs: the number of arguments
6441 *
6442 * Implement the string() XPath function
6443 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006444 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006445 * - A node-set is converted to a string by returning the value of
6446 * the node in the node-set that is first in document order.
6447 * If the node-set is empty, an empty string is returned.
6448 * - A number is converted to a string as follows
6449 * + NaN is converted to the string NaN
6450 * + positive zero is converted to the string 0
6451 * + negative zero is converted to the string 0
6452 * + positive infinity is converted to the string Infinity
6453 * + negative infinity is converted to the string -Infinity
6454 * + if the number is an integer, the number is represented in
6455 * decimal form as a Number with no decimal point and no leading
6456 * zeros, preceded by a minus sign (-) if the number is negative
6457 * + otherwise, the number is represented in decimal form as a
6458 * Number including a decimal point with at least one digit
6459 * before the decimal point and at least one digit after the
6460 * decimal point, preceded by a minus sign (-) if the number
6461 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006462 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006463 * before the decimal point; beyond the one required digit
6464 * after the decimal point there must be as many, but only as
6465 * many, more digits as are needed to uniquely distinguish the
6466 * number from all other IEEE 754 numeric values.
6467 * - The boolean false value is converted to the string false.
6468 * The boolean true value is converted to the string true.
6469 *
6470 * If the argument is omitted, it defaults to a node-set with the
6471 * context node as its only member.
6472 */
6473void
6474xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6475 xmlXPathObjectPtr cur;
6476
Daniel Veillarda82b1822004-11-08 16:24:57 +00006477 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006478 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006479 valuePush(ctxt,
6480 xmlXPathWrapString(
6481 xmlXPathCastNodeToString(ctxt->context->node)));
6482 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006483 }
6484
6485 CHECK_ARITY(1);
6486 cur = valuePop(ctxt);
6487 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006488 cur = xmlXPathConvertString(cur);
6489 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006490}
6491
6492/**
6493 * xmlXPathStringLengthFunction:
6494 * @ctxt: the XPath Parser context
6495 * @nargs: the number of arguments
6496 *
6497 * Implement the string-length() XPath function
6498 * number string-length(string?)
6499 * The string-length returns the number of characters in the string
6500 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6501 * the context node converted to a string, in other words the value
6502 * of the context node.
6503 */
6504void
6505xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6506 xmlXPathObjectPtr cur;
6507
6508 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006509 if ((ctxt == NULL) || (ctxt->context == NULL))
6510 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006511 if (ctxt->context->node == NULL) {
6512 valuePush(ctxt, xmlXPathNewFloat(0));
6513 } else {
6514 xmlChar *content;
6515
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006516 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006517 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006518 xmlFree(content);
6519 }
6520 return;
6521 }
6522 CHECK_ARITY(1);
6523 CAST_TO_STRING;
6524 CHECK_TYPE(XPATH_STRING);
6525 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006526 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006527 xmlXPathFreeObject(cur);
6528}
6529
6530/**
6531 * xmlXPathConcatFunction:
6532 * @ctxt: the XPath Parser context
6533 * @nargs: the number of arguments
6534 *
6535 * Implement the concat() XPath function
6536 * string concat(string, string, string*)
6537 * The concat function returns the concatenation of its arguments.
6538 */
6539void
6540xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6541 xmlXPathObjectPtr cur, newobj;
6542 xmlChar *tmp;
6543
Daniel Veillarda82b1822004-11-08 16:24:57 +00006544 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006545 if (nargs < 2) {
6546 CHECK_ARITY(2);
6547 }
6548
6549 CAST_TO_STRING;
6550 cur = valuePop(ctxt);
6551 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6552 xmlXPathFreeObject(cur);
6553 return;
6554 }
6555 nargs--;
6556
6557 while (nargs > 0) {
6558 CAST_TO_STRING;
6559 newobj = valuePop(ctxt);
6560 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6561 xmlXPathFreeObject(newobj);
6562 xmlXPathFreeObject(cur);
6563 XP_ERROR(XPATH_INVALID_TYPE);
6564 }
6565 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6566 newobj->stringval = cur->stringval;
6567 cur->stringval = tmp;
6568
6569 xmlXPathFreeObject(newobj);
6570 nargs--;
6571 }
6572 valuePush(ctxt, cur);
6573}
6574
6575/**
6576 * xmlXPathContainsFunction:
6577 * @ctxt: the XPath Parser context
6578 * @nargs: the number of arguments
6579 *
6580 * Implement the contains() XPath function
6581 * boolean contains(string, string)
6582 * The contains function returns true if the first argument string
6583 * contains the second argument string, and otherwise returns false.
6584 */
6585void
6586xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6587 xmlXPathObjectPtr hay, needle;
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 if (xmlStrstr(hay->stringval, needle->stringval))
6601 valuePush(ctxt, xmlXPathNewBoolean(1));
6602 else
6603 valuePush(ctxt, xmlXPathNewBoolean(0));
6604 xmlXPathFreeObject(hay);
6605 xmlXPathFreeObject(needle);
6606}
6607
6608/**
6609 * xmlXPathStartsWithFunction:
6610 * @ctxt: the XPath Parser context
6611 * @nargs: the number of arguments
6612 *
6613 * Implement the starts-with() XPath function
6614 * boolean starts-with(string, string)
6615 * The starts-with function returns true if the first argument string
6616 * starts with the second argument string, and otherwise returns false.
6617 */
6618void
6619xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6620 xmlXPathObjectPtr hay, needle;
6621 int n;
6622
6623 CHECK_ARITY(2);
6624 CAST_TO_STRING;
6625 CHECK_TYPE(XPATH_STRING);
6626 needle = valuePop(ctxt);
6627 CAST_TO_STRING;
6628 hay = valuePop(ctxt);
6629 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6630 xmlXPathFreeObject(hay);
6631 xmlXPathFreeObject(needle);
6632 XP_ERROR(XPATH_INVALID_TYPE);
6633 }
6634 n = xmlStrlen(needle->stringval);
6635 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6636 valuePush(ctxt, xmlXPathNewBoolean(0));
6637 else
6638 valuePush(ctxt, xmlXPathNewBoolean(1));
6639 xmlXPathFreeObject(hay);
6640 xmlXPathFreeObject(needle);
6641}
6642
6643/**
6644 * xmlXPathSubstringFunction:
6645 * @ctxt: the XPath Parser context
6646 * @nargs: the number of arguments
6647 *
6648 * Implement the substring() XPath function
6649 * string substring(string, number, number?)
6650 * The substring function returns the substring of the first argument
6651 * starting at the position specified in the second argument with
6652 * length specified in the third argument. For example,
6653 * substring("12345",2,3) returns "234". If the third argument is not
6654 * specified, it returns the substring starting at the position specified
6655 * in the second argument and continuing to the end of the string. For
6656 * example, substring("12345",2) returns "2345". More precisely, each
6657 * character in the string (see [3.6 Strings]) is considered to have a
6658 * numeric position: the position of the first character is 1, the position
6659 * of the second character is 2 and so on. The returned substring contains
6660 * those characters for which the position of the character is greater than
6661 * or equal to the second argument and, if the third argument is specified,
6662 * less than the sum of the second and third arguments; the comparisons
6663 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6664 * - substring("12345", 1.5, 2.6) returns "234"
6665 * - substring("12345", 0, 3) returns "12"
6666 * - substring("12345", 0 div 0, 3) returns ""
6667 * - substring("12345", 1, 0 div 0) returns ""
6668 * - substring("12345", -42, 1 div 0) returns "12345"
6669 * - substring("12345", -1 div 0, 1 div 0) returns ""
6670 */
6671void
6672xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6673 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006674 double le=0, in;
6675 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006676 xmlChar *ret;
6677
Owen Taylor3473f882001-02-23 17:55:21 +00006678 if (nargs < 2) {
6679 CHECK_ARITY(2);
6680 }
6681 if (nargs > 3) {
6682 CHECK_ARITY(3);
6683 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006684 /*
6685 * take care of possible last (position) argument
6686 */
Owen Taylor3473f882001-02-23 17:55:21 +00006687 if (nargs == 3) {
6688 CAST_TO_NUMBER;
6689 CHECK_TYPE(XPATH_NUMBER);
6690 len = valuePop(ctxt);
6691 le = len->floatval;
6692 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006693 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006694
Owen Taylor3473f882001-02-23 17:55:21 +00006695 CAST_TO_NUMBER;
6696 CHECK_TYPE(XPATH_NUMBER);
6697 start = valuePop(ctxt);
6698 in = start->floatval;
6699 xmlXPathFreeObject(start);
6700 CAST_TO_STRING;
6701 CHECK_TYPE(XPATH_STRING);
6702 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006703 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006704
Daniel Veillard97ac1312001-05-30 19:14:17 +00006705 /*
6706 * If last pos not present, calculate last position
6707 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006708 if (nargs != 3) {
6709 le = (double)m;
6710 if (in < 1.0)
6711 in = 1.0;
6712 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006713
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006714 /* Need to check for the special cases where either
6715 * the index is NaN, the length is NaN, or both
6716 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006717 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006718 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006719 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006720 * To meet the requirements of the spec, the arguments
6721 * must be converted to integer format before
6722 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006723 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006724 * First we go to integer form, rounding up
6725 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006726 */
6727 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006728 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006729
Daniel Veillard9e412302002-06-10 15:59:44 +00006730 if (xmlXPathIsInf(le) == 1) {
6731 l = m;
6732 if (i < 1)
6733 i = 1;
6734 }
6735 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6736 l = 0;
6737 else {
6738 l = (int) le;
6739 if (((double)l)+0.5 <= le) l++;
6740 }
6741
6742 /* Now we normalize inidices */
6743 i -= 1;
6744 l += i;
6745 if (i < 0)
6746 i = 0;
6747 if (l > m)
6748 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006749
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006750 /* number of chars to copy */
6751 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006752
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006753 ret = xmlUTF8Strsub(str->stringval, i, l);
6754 }
6755 else {
6756 ret = NULL;
6757 }
6758
Owen Taylor3473f882001-02-23 17:55:21 +00006759 if (ret == NULL)
6760 valuePush(ctxt, xmlXPathNewCString(""));
6761 else {
6762 valuePush(ctxt, xmlXPathNewString(ret));
6763 xmlFree(ret);
6764 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006765
Owen Taylor3473f882001-02-23 17:55:21 +00006766 xmlXPathFreeObject(str);
6767}
6768
6769/**
6770 * xmlXPathSubstringBeforeFunction:
6771 * @ctxt: the XPath Parser context
6772 * @nargs: the number of arguments
6773 *
6774 * Implement the substring-before() XPath function
6775 * string substring-before(string, string)
6776 * The substring-before function returns the substring of the first
6777 * argument string that precedes the first occurrence of the second
6778 * argument string in the first argument string, or the empty string
6779 * if the first argument string does not contain the second argument
6780 * string. For example, substring-before("1999/04/01","/") returns 1999.
6781 */
6782void
6783xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6784 xmlXPathObjectPtr str;
6785 xmlXPathObjectPtr find;
6786 xmlBufferPtr target;
6787 const xmlChar *point;
6788 int offset;
6789
6790 CHECK_ARITY(2);
6791 CAST_TO_STRING;
6792 find = valuePop(ctxt);
6793 CAST_TO_STRING;
6794 str = valuePop(ctxt);
6795
6796 target = xmlBufferCreate();
6797 if (target) {
6798 point = xmlStrstr(str->stringval, find->stringval);
6799 if (point) {
6800 offset = (int)(point - str->stringval);
6801 xmlBufferAdd(target, str->stringval, offset);
6802 }
6803 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6804 xmlBufferFree(target);
6805 }
6806
6807 xmlXPathFreeObject(str);
6808 xmlXPathFreeObject(find);
6809}
6810
6811/**
6812 * xmlXPathSubstringAfterFunction:
6813 * @ctxt: the XPath Parser context
6814 * @nargs: the number of arguments
6815 *
6816 * Implement the substring-after() XPath function
6817 * string substring-after(string, string)
6818 * The substring-after function returns the substring of the first
6819 * argument string that follows the first occurrence of the second
6820 * argument string in the first argument string, or the empty stringi
6821 * if the first argument string does not contain the second argument
6822 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6823 * and substring-after("1999/04/01","19") returns 99/04/01.
6824 */
6825void
6826xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6827 xmlXPathObjectPtr str;
6828 xmlXPathObjectPtr find;
6829 xmlBufferPtr target;
6830 const xmlChar *point;
6831 int offset;
6832
6833 CHECK_ARITY(2);
6834 CAST_TO_STRING;
6835 find = valuePop(ctxt);
6836 CAST_TO_STRING;
6837 str = valuePop(ctxt);
6838
6839 target = xmlBufferCreate();
6840 if (target) {
6841 point = xmlStrstr(str->stringval, find->stringval);
6842 if (point) {
6843 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6844 xmlBufferAdd(target, &str->stringval[offset],
6845 xmlStrlen(str->stringval) - offset);
6846 }
6847 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6848 xmlBufferFree(target);
6849 }
6850
6851 xmlXPathFreeObject(str);
6852 xmlXPathFreeObject(find);
6853}
6854
6855/**
6856 * xmlXPathNormalizeFunction:
6857 * @ctxt: the XPath Parser context
6858 * @nargs: the number of arguments
6859 *
6860 * Implement the normalize-space() XPath function
6861 * string normalize-space(string?)
6862 * The normalize-space function returns the argument string with white
6863 * space normalized by stripping leading and trailing whitespace
6864 * and replacing sequences of whitespace characters by a single
6865 * space. Whitespace characters are the same allowed by the S production
6866 * in XML. If the argument is omitted, it defaults to the context
6867 * node converted to a string, in other words the value of the context node.
6868 */
6869void
6870xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6871 xmlXPathObjectPtr obj = NULL;
6872 xmlChar *source = NULL;
6873 xmlBufferPtr target;
6874 xmlChar blank;
6875
Daniel Veillarda82b1822004-11-08 16:24:57 +00006876 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006877 if (nargs == 0) {
6878 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006879 valuePush(ctxt,
6880 xmlXPathWrapString(
6881 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006882 nargs = 1;
6883 }
6884
6885 CHECK_ARITY(1);
6886 CAST_TO_STRING;
6887 CHECK_TYPE(XPATH_STRING);
6888 obj = valuePop(ctxt);
6889 source = obj->stringval;
6890
6891 target = xmlBufferCreate();
6892 if (target && source) {
6893
6894 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006895 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006896 source++;
6897
6898 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6899 blank = 0;
6900 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006901 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006902 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006903 } else {
6904 if (blank) {
6905 xmlBufferAdd(target, &blank, 1);
6906 blank = 0;
6907 }
6908 xmlBufferAdd(target, source, 1);
6909 }
6910 source++;
6911 }
6912
6913 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6914 xmlBufferFree(target);
6915 }
6916 xmlXPathFreeObject(obj);
6917}
6918
6919/**
6920 * xmlXPathTranslateFunction:
6921 * @ctxt: the XPath Parser context
6922 * @nargs: the number of arguments
6923 *
6924 * Implement the translate() XPath function
6925 * string translate(string, string, string)
6926 * The translate function returns the first argument string with
6927 * occurrences of characters in the second argument string replaced
6928 * by the character at the corresponding position in the third argument
6929 * string. For example, translate("bar","abc","ABC") returns the string
6930 * BAr. If there is a character in the second argument string with no
6931 * character at a corresponding position in the third argument string
6932 * (because the second argument string is longer than the third argument
6933 * string), then occurrences of that character in the first argument
6934 * string are removed. For example, translate("--aaa--","abc-","ABC")
6935 * returns "AAA". If a character occurs more than once in second
6936 * argument string, then the first occurrence determines the replacement
6937 * character. If the third argument string is longer than the second
6938 * argument string, then excess characters are ignored.
6939 */
6940void
6941xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006942 xmlXPathObjectPtr str;
6943 xmlXPathObjectPtr from;
6944 xmlXPathObjectPtr to;
6945 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006946 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006947 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00006948 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006949 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006950
Daniel Veillarde043ee12001-04-16 14:08:07 +00006951 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006952
Daniel Veillarde043ee12001-04-16 14:08:07 +00006953 CAST_TO_STRING;
6954 to = valuePop(ctxt);
6955 CAST_TO_STRING;
6956 from = valuePop(ctxt);
6957 CAST_TO_STRING;
6958 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006959
Daniel Veillarde043ee12001-04-16 14:08:07 +00006960 target = xmlBufferCreate();
6961 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006962 max = xmlUTF8Strlen(to->stringval);
6963 for (cptr = str->stringval; (ch=*cptr); ) {
6964 offset = xmlUTF8Strloc(from->stringval, cptr);
6965 if (offset >= 0) {
6966 if (offset < max) {
6967 point = xmlUTF8Strpos(to->stringval, offset);
6968 if (point)
6969 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6970 }
6971 } else
6972 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6973
6974 /* Step to next character in input */
6975 cptr++;
6976 if ( ch & 0x80 ) {
6977 /* if not simple ascii, verify proper format */
6978 if ( (ch & 0xc0) != 0xc0 ) {
6979 xmlGenericError(xmlGenericErrorContext,
6980 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6981 break;
6982 }
6983 /* then skip over remaining bytes for this char */
6984 while ( (ch <<= 1) & 0x80 )
6985 if ( (*cptr++ & 0xc0) != 0x80 ) {
6986 xmlGenericError(xmlGenericErrorContext,
6987 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6988 break;
6989 }
6990 if (ch & 0x80) /* must have had error encountered */
6991 break;
6992 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006993 }
Owen Taylor3473f882001-02-23 17:55:21 +00006994 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006995 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6996 xmlBufferFree(target);
6997 xmlXPathFreeObject(str);
6998 xmlXPathFreeObject(from);
6999 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00007000}
7001
7002/**
7003 * xmlXPathBooleanFunction:
7004 * @ctxt: the XPath Parser context
7005 * @nargs: the number of arguments
7006 *
7007 * Implement the boolean() XPath function
7008 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00007009 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00007010 * - a number is true if and only if it is neither positive or
7011 * negative zero nor NaN
7012 * - a node-set is true if and only if it is non-empty
7013 * - a string is true if and only if its length is non-zero
7014 */
7015void
7016xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7017 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00007018
7019 CHECK_ARITY(1);
7020 cur = valuePop(ctxt);
7021 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007022 cur = xmlXPathConvertBoolean(cur);
7023 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007024}
7025
7026/**
7027 * xmlXPathNotFunction:
7028 * @ctxt: the XPath Parser context
7029 * @nargs: the number of arguments
7030 *
7031 * Implement the not() XPath function
7032 * boolean not(boolean)
7033 * The not function returns true if its argument is false,
7034 * and false otherwise.
7035 */
7036void
7037xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7038 CHECK_ARITY(1);
7039 CAST_TO_BOOLEAN;
7040 CHECK_TYPE(XPATH_BOOLEAN);
7041 ctxt->value->boolval = ! ctxt->value->boolval;
7042}
7043
7044/**
7045 * xmlXPathTrueFunction:
7046 * @ctxt: the XPath Parser context
7047 * @nargs: the number of arguments
7048 *
7049 * Implement the true() XPath function
7050 * boolean true()
7051 */
7052void
7053xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7054 CHECK_ARITY(0);
7055 valuePush(ctxt, xmlXPathNewBoolean(1));
7056}
7057
7058/**
7059 * xmlXPathFalseFunction:
7060 * @ctxt: the XPath Parser context
7061 * @nargs: the number of arguments
7062 *
7063 * Implement the false() XPath function
7064 * boolean false()
7065 */
7066void
7067xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7068 CHECK_ARITY(0);
7069 valuePush(ctxt, xmlXPathNewBoolean(0));
7070}
7071
7072/**
7073 * xmlXPathLangFunction:
7074 * @ctxt: the XPath Parser context
7075 * @nargs: the number of arguments
7076 *
7077 * Implement the lang() XPath function
7078 * boolean lang(string)
7079 * The lang function returns true or false depending on whether the
7080 * language of the context node as specified by xml:lang attributes
7081 * is the same as or is a sublanguage of the language specified by
7082 * the argument string. The language of the context node is determined
7083 * by the value of the xml:lang attribute on the context node, or, if
7084 * the context node has no xml:lang attribute, by the value of the
7085 * xml:lang attribute on the nearest ancestor of the context node that
7086 * has an xml:lang attribute. If there is no such attribute, then lang
7087 * returns false. If there is such an attribute, then lang returns
7088 * true if the attribute value is equal to the argument ignoring case,
7089 * or if there is some suffix starting with - such that the attribute
7090 * value is equal to the argument ignoring that suffix of the attribute
7091 * value and ignoring case.
7092 */
7093void
7094xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7095 xmlXPathObjectPtr val;
7096 const xmlChar *theLang;
7097 const xmlChar *lang;
7098 int ret = 0;
7099 int i;
7100
7101 CHECK_ARITY(1);
7102 CAST_TO_STRING;
7103 CHECK_TYPE(XPATH_STRING);
7104 val = valuePop(ctxt);
7105 lang = val->stringval;
7106 theLang = xmlNodeGetLang(ctxt->context->node);
7107 if ((theLang != NULL) && (lang != NULL)) {
7108 for (i = 0;lang[i] != 0;i++)
7109 if (toupper(lang[i]) != toupper(theLang[i]))
7110 goto not_equal;
7111 ret = 1;
7112 }
7113not_equal:
William M. Bracka59ddb52004-02-25 08:12:32 +00007114 xmlFree((void *)theLang);
Owen Taylor3473f882001-02-23 17:55:21 +00007115 xmlXPathFreeObject(val);
7116 valuePush(ctxt, xmlXPathNewBoolean(ret));
7117}
7118
7119/**
7120 * xmlXPathNumberFunction:
7121 * @ctxt: the XPath Parser context
7122 * @nargs: the number of arguments
7123 *
7124 * Implement the number() XPath function
7125 * number number(object?)
7126 */
7127void
7128xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7129 xmlXPathObjectPtr cur;
7130 double res;
7131
Daniel Veillarda82b1822004-11-08 16:24:57 +00007132 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007133 if (nargs == 0) {
7134 if (ctxt->context->node == NULL) {
7135 valuePush(ctxt, xmlXPathNewFloat(0.0));
7136 } else {
7137 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7138
7139 res = xmlXPathStringEvalNumber(content);
7140 valuePush(ctxt, xmlXPathNewFloat(res));
7141 xmlFree(content);
7142 }
7143 return;
7144 }
7145
7146 CHECK_ARITY(1);
7147 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007148 cur = xmlXPathConvertNumber(cur);
7149 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007150}
7151
7152/**
7153 * xmlXPathSumFunction:
7154 * @ctxt: the XPath Parser context
7155 * @nargs: the number of arguments
7156 *
7157 * Implement the sum() XPath function
7158 * number sum(node-set)
7159 * The sum function returns the sum of the values of the nodes in
7160 * the argument node-set.
7161 */
7162void
7163xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7164 xmlXPathObjectPtr cur;
7165 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007166 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007167
7168 CHECK_ARITY(1);
7169 if ((ctxt->value == NULL) ||
7170 ((ctxt->value->type != XPATH_NODESET) &&
7171 (ctxt->value->type != XPATH_XSLT_TREE)))
7172 XP_ERROR(XPATH_INVALID_TYPE);
7173 cur = valuePop(ctxt);
7174
William M. Brack08171912003-12-29 02:52:11 +00007175 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007176 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7177 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007178 }
7179 }
William M. Brack08171912003-12-29 02:52:11 +00007180 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007181 xmlXPathFreeObject(cur);
7182}
7183
7184/**
7185 * xmlXPathFloorFunction:
7186 * @ctxt: the XPath Parser context
7187 * @nargs: the number of arguments
7188 *
7189 * Implement the floor() XPath function
7190 * number floor(number)
7191 * The floor function returns the largest (closest to positive infinity)
7192 * number that is not greater than the argument and that is an integer.
7193 */
7194void
7195xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007196 double f;
7197
Owen Taylor3473f882001-02-23 17:55:21 +00007198 CHECK_ARITY(1);
7199 CAST_TO_NUMBER;
7200 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007201
7202 f = (double)((int) ctxt->value->floatval);
7203 if (f != ctxt->value->floatval) {
7204 if (ctxt->value->floatval > 0)
7205 ctxt->value->floatval = f;
7206 else
7207 ctxt->value->floatval = f - 1;
7208 }
Owen Taylor3473f882001-02-23 17:55:21 +00007209}
7210
7211/**
7212 * xmlXPathCeilingFunction:
7213 * @ctxt: the XPath Parser context
7214 * @nargs: the number of arguments
7215 *
7216 * Implement the ceiling() XPath function
7217 * number ceiling(number)
7218 * The ceiling function returns the smallest (closest to negative infinity)
7219 * number that is not less than the argument and that is an integer.
7220 */
7221void
7222xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7223 double f;
7224
7225 CHECK_ARITY(1);
7226 CAST_TO_NUMBER;
7227 CHECK_TYPE(XPATH_NUMBER);
7228
7229#if 0
7230 ctxt->value->floatval = ceil(ctxt->value->floatval);
7231#else
7232 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007233 if (f != ctxt->value->floatval) {
7234 if (ctxt->value->floatval > 0)
7235 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007236 else {
7237 if (ctxt->value->floatval < 0 && f == 0)
7238 ctxt->value->floatval = xmlXPathNZERO;
7239 else
7240 ctxt->value->floatval = f;
7241 }
7242
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007243 }
Owen Taylor3473f882001-02-23 17:55:21 +00007244#endif
7245}
7246
7247/**
7248 * xmlXPathRoundFunction:
7249 * @ctxt: the XPath Parser context
7250 * @nargs: the number of arguments
7251 *
7252 * Implement the round() XPath function
7253 * number round(number)
7254 * The round function returns the number that is closest to the
7255 * argument and that is an integer. If there are two such numbers,
7256 * then the one that is even is returned.
7257 */
7258void
7259xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7260 double f;
7261
7262 CHECK_ARITY(1);
7263 CAST_TO_NUMBER;
7264 CHECK_TYPE(XPATH_NUMBER);
7265
Daniel Veillardcda96922001-08-21 10:56:31 +00007266 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7267 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7268 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007269 (ctxt->value->floatval == 0.0))
7270 return;
7271
Owen Taylor3473f882001-02-23 17:55:21 +00007272 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007273 if (ctxt->value->floatval < 0) {
7274 if (ctxt->value->floatval < f - 0.5)
7275 ctxt->value->floatval = f - 1;
7276 else
7277 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007278 if (ctxt->value->floatval == 0)
7279 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007280 } else {
7281 if (ctxt->value->floatval < f + 0.5)
7282 ctxt->value->floatval = f;
7283 else
7284 ctxt->value->floatval = f + 1;
7285 }
Owen Taylor3473f882001-02-23 17:55:21 +00007286}
7287
7288/************************************************************************
7289 * *
7290 * The Parser *
7291 * *
7292 ************************************************************************/
7293
7294/*
William M. Brack08171912003-12-29 02:52:11 +00007295 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007296 * implementation.
7297 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007298static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007299static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007300static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007301static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007302static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7303 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007304
7305/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007306 * xmlXPathCurrentChar:
7307 * @ctxt: the XPath parser context
7308 * @cur: pointer to the beginning of the char
7309 * @len: pointer to the length of the char read
7310 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007311 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007312 * bytes in the input buffer.
7313 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007314 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007315 */
7316
7317static int
7318xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7319 unsigned char c;
7320 unsigned int val;
7321 const xmlChar *cur;
7322
7323 if (ctxt == NULL)
7324 return(0);
7325 cur = ctxt->cur;
7326
7327 /*
7328 * We are supposed to handle UTF8, check it's valid
7329 * From rfc2044: encoding of the Unicode values on UTF-8:
7330 *
7331 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7332 * 0000 0000-0000 007F 0xxxxxxx
7333 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7334 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7335 *
7336 * Check for the 0x110000 limit too
7337 */
7338 c = *cur;
7339 if (c & 0x80) {
7340 if ((cur[1] & 0xc0) != 0x80)
7341 goto encoding_error;
7342 if ((c & 0xe0) == 0xe0) {
7343
7344 if ((cur[2] & 0xc0) != 0x80)
7345 goto encoding_error;
7346 if ((c & 0xf0) == 0xf0) {
7347 if (((c & 0xf8) != 0xf0) ||
7348 ((cur[3] & 0xc0) != 0x80))
7349 goto encoding_error;
7350 /* 4-byte code */
7351 *len = 4;
7352 val = (cur[0] & 0x7) << 18;
7353 val |= (cur[1] & 0x3f) << 12;
7354 val |= (cur[2] & 0x3f) << 6;
7355 val |= cur[3] & 0x3f;
7356 } else {
7357 /* 3-byte code */
7358 *len = 3;
7359 val = (cur[0] & 0xf) << 12;
7360 val |= (cur[1] & 0x3f) << 6;
7361 val |= cur[2] & 0x3f;
7362 }
7363 } else {
7364 /* 2-byte code */
7365 *len = 2;
7366 val = (cur[0] & 0x1f) << 6;
7367 val |= cur[1] & 0x3f;
7368 }
7369 if (!IS_CHAR(val)) {
7370 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7371 }
7372 return(val);
7373 } else {
7374 /* 1-byte code */
7375 *len = 1;
7376 return((int) *cur);
7377 }
7378encoding_error:
7379 /*
William M. Brack08171912003-12-29 02:52:11 +00007380 * If we detect an UTF8 error that probably means that the
7381 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007382 * declaration header. Report the error and switch the encoding
7383 * to ISO-Latin-1 (if you don't like this policy, just declare the
7384 * encoding !)
7385 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007386 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007387 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007388}
7389
7390/**
Owen Taylor3473f882001-02-23 17:55:21 +00007391 * xmlXPathParseNCName:
7392 * @ctxt: the XPath Parser context
7393 *
7394 * parse an XML namespace non qualified name.
7395 *
7396 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7397 *
7398 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7399 * CombiningChar | Extender
7400 *
7401 * Returns the namespace name or NULL
7402 */
7403
7404xmlChar *
7405xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007406 const xmlChar *in;
7407 xmlChar *ret;
7408 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007409
Daniel Veillarda82b1822004-11-08 16:24:57 +00007410 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00007411 /*
7412 * Accelerator for simple ASCII names
7413 */
7414 in = ctxt->cur;
7415 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7416 ((*in >= 0x41) && (*in <= 0x5A)) ||
7417 (*in == '_')) {
7418 in++;
7419 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7420 ((*in >= 0x41) && (*in <= 0x5A)) ||
7421 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007422 (*in == '_') || (*in == '.') ||
7423 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007424 in++;
7425 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7426 (*in == '[') || (*in == ']') || (*in == ':') ||
7427 (*in == '@') || (*in == '*')) {
7428 count = in - ctxt->cur;
7429 if (count == 0)
7430 return(NULL);
7431 ret = xmlStrndup(ctxt->cur, count);
7432 ctxt->cur = in;
7433 return(ret);
7434 }
7435 }
7436 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007437}
7438
Daniel Veillard2156a562001-04-28 12:24:34 +00007439
Owen Taylor3473f882001-02-23 17:55:21 +00007440/**
7441 * xmlXPathParseQName:
7442 * @ctxt: the XPath Parser context
7443 * @prefix: a xmlChar **
7444 *
7445 * parse an XML qualified name
7446 *
7447 * [NS 5] QName ::= (Prefix ':')? LocalPart
7448 *
7449 * [NS 6] Prefix ::= NCName
7450 *
7451 * [NS 7] LocalPart ::= NCName
7452 *
7453 * Returns the function returns the local part, and prefix is updated
7454 * to get the Prefix if any.
7455 */
7456
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007457static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007458xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7459 xmlChar *ret = NULL;
7460
7461 *prefix = NULL;
7462 ret = xmlXPathParseNCName(ctxt);
7463 if (CUR == ':') {
7464 *prefix = ret;
7465 NEXT;
7466 ret = xmlXPathParseNCName(ctxt);
7467 }
7468 return(ret);
7469}
7470
7471/**
7472 * xmlXPathParseName:
7473 * @ctxt: the XPath Parser context
7474 *
7475 * parse an XML name
7476 *
7477 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7478 * CombiningChar | Extender
7479 *
7480 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7481 *
7482 * Returns the namespace name or NULL
7483 */
7484
7485xmlChar *
7486xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007487 const xmlChar *in;
7488 xmlChar *ret;
7489 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007490
Daniel Veillarda82b1822004-11-08 16:24:57 +00007491 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007492 /*
7493 * Accelerator for simple ASCII names
7494 */
7495 in = ctxt->cur;
7496 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7497 ((*in >= 0x41) && (*in <= 0x5A)) ||
7498 (*in == '_') || (*in == ':')) {
7499 in++;
7500 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7501 ((*in >= 0x41) && (*in <= 0x5A)) ||
7502 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007503 (*in == '_') || (*in == '-') ||
7504 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007505 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007506 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007507 count = in - ctxt->cur;
7508 ret = xmlStrndup(ctxt->cur, count);
7509 ctxt->cur = in;
7510 return(ret);
7511 }
7512 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007513 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007514}
7515
Daniel Veillard61d80a22001-04-27 17:13:01 +00007516static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007517xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007518 xmlChar buf[XML_MAX_NAMELEN + 5];
7519 int len = 0, l;
7520 int c;
7521
7522 /*
7523 * Handler for more complex cases
7524 */
7525 c = CUR_CHAR(l);
7526 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007527 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7528 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007529 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007530 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007531 return(NULL);
7532 }
7533
7534 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7535 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7536 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007537 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007538 (IS_COMBINING(c)) ||
7539 (IS_EXTENDER(c)))) {
7540 COPY_BUF(l,buf,len,c);
7541 NEXTL(l);
7542 c = CUR_CHAR(l);
7543 if (len >= XML_MAX_NAMELEN) {
7544 /*
7545 * Okay someone managed to make a huge name, so he's ready to pay
7546 * for the processing speed.
7547 */
7548 xmlChar *buffer;
7549 int max = len * 2;
7550
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007551 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007552 if (buffer == NULL) {
7553 XP_ERROR0(XPATH_MEMORY_ERROR);
7554 }
7555 memcpy(buffer, buf, len);
7556 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7557 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007558 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007559 (IS_COMBINING(c)) ||
7560 (IS_EXTENDER(c))) {
7561 if (len + 10 > max) {
7562 max *= 2;
7563 buffer = (xmlChar *) xmlRealloc(buffer,
7564 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007565 if (buffer == NULL) {
7566 XP_ERROR0(XPATH_MEMORY_ERROR);
7567 }
7568 }
7569 COPY_BUF(l,buffer,len,c);
7570 NEXTL(l);
7571 c = CUR_CHAR(l);
7572 }
7573 buffer[len] = 0;
7574 return(buffer);
7575 }
7576 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007577 if (len == 0)
7578 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007579 return(xmlStrndup(buf, len));
7580}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007581
7582#define MAX_FRAC 20
7583
William M. Brack372a4452004-02-17 13:09:23 +00007584/*
7585 * These are used as divisors for the fractional part of a number.
7586 * Since the table includes 1.0 (representing '0' fractional digits),
7587 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
7588 */
7589static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007590 1.0, 10.0, 100.0, 1000.0, 10000.0,
7591 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7592 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7593 100000000000000.0,
7594 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00007595 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00007596};
7597
Owen Taylor3473f882001-02-23 17:55:21 +00007598/**
7599 * xmlXPathStringEvalNumber:
7600 * @str: A string to scan
7601 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007602 * [30a] Float ::= Number ('e' Digits?)?
7603 *
Owen Taylor3473f882001-02-23 17:55:21 +00007604 * [30] Number ::= Digits ('.' Digits?)?
7605 * | '.' Digits
7606 * [31] Digits ::= [0-9]+
7607 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007608 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007609 * In complement of the Number expression, this function also handles
7610 * negative values : '-' Number.
7611 *
7612 * Returns the double value.
7613 */
7614double
7615xmlXPathStringEvalNumber(const xmlChar *str) {
7616 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007617 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007618 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007619 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007620 int exponent = 0;
7621 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007622#ifdef __GNUC__
7623 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007624 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007625#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007626 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007627 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007628 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7629 return(xmlXPathNAN);
7630 }
7631 if (*cur == '-') {
7632 isneg = 1;
7633 cur++;
7634 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007635
7636#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007637 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007638 * tmp/temp is a workaround against a gcc compiler bug
7639 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007640 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007641 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007642 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007643 ret = ret * 10;
7644 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007645 ok = 1;
7646 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007647 temp = (double) tmp;
7648 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007649 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007650#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007651 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007652 while ((*cur >= '0') && (*cur <= '9')) {
7653 ret = ret * 10 + (*cur - '0');
7654 ok = 1;
7655 cur++;
7656 }
7657#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007658
Owen Taylor3473f882001-02-23 17:55:21 +00007659 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007660 int v, frac = 0;
7661 double fraction = 0;
7662
Owen Taylor3473f882001-02-23 17:55:21 +00007663 cur++;
7664 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7665 return(xmlXPathNAN);
7666 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007667 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7668 v = (*cur - '0');
7669 fraction = fraction * 10 + v;
7670 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007671 cur++;
7672 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007673 fraction /= my_pow10[frac];
7674 ret = ret + fraction;
7675 while ((*cur >= '0') && (*cur <= '9'))
7676 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007677 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007678 if ((*cur == 'e') || (*cur == 'E')) {
7679 cur++;
7680 if (*cur == '-') {
7681 is_exponent_negative = 1;
7682 cur++;
William M. Brack99127052004-05-24 02:52:28 +00007683 } else if (*cur == '+') {
7684 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007685 }
7686 while ((*cur >= '0') && (*cur <= '9')) {
7687 exponent = exponent * 10 + (*cur - '0');
7688 cur++;
7689 }
7690 }
William M. Brack76e95df2003-10-18 16:20:14 +00007691 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007692 if (*cur != 0) return(xmlXPathNAN);
7693 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007694 if (is_exponent_negative) exponent = -exponent;
7695 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007696 return(ret);
7697}
7698
7699/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007700 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007701 * @ctxt: the XPath Parser context
7702 *
7703 * [30] Number ::= Digits ('.' Digits?)?
7704 * | '.' Digits
7705 * [31] Digits ::= [0-9]+
7706 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007707 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007708 *
7709 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007710static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007711xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7712{
Owen Taylor3473f882001-02-23 17:55:21 +00007713 double ret = 0.0;
7714 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007715 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007716 int exponent = 0;
7717 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007718#ifdef __GNUC__
7719 unsigned long tmp = 0;
7720 double temp;
7721#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007722
7723 CHECK_ERROR;
7724 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7725 XP_ERROR(XPATH_NUMBER_ERROR);
7726 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007727#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007728 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007729 * tmp/temp is a workaround against a gcc compiler bug
7730 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007731 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007732 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007733 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007734 ret = ret * 10;
7735 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007736 ok = 1;
7737 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007738 temp = (double) tmp;
7739 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007740 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007741#else
7742 ret = 0;
7743 while ((CUR >= '0') && (CUR <= '9')) {
7744 ret = ret * 10 + (CUR - '0');
7745 ok = 1;
7746 NEXT;
7747 }
7748#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007749 if (CUR == '.') {
7750 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007751 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7752 XP_ERROR(XPATH_NUMBER_ERROR);
7753 }
7754 while ((CUR >= '0') && (CUR <= '9')) {
7755 mult /= 10;
7756 ret = ret + (CUR - '0') * mult;
7757 NEXT;
7758 }
Owen Taylor3473f882001-02-23 17:55:21 +00007759 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007760 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007761 NEXT;
7762 if (CUR == '-') {
7763 is_exponent_negative = 1;
7764 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00007765 } else if (CUR == '+') {
7766 NEXT;
7767 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007768 while ((CUR >= '0') && (CUR <= '9')) {
7769 exponent = exponent * 10 + (CUR - '0');
7770 NEXT;
7771 }
7772 if (is_exponent_negative)
7773 exponent = -exponent;
7774 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007775 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007776 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007777 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007778}
7779
7780/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007781 * xmlXPathParseLiteral:
7782 * @ctxt: the XPath Parser context
7783 *
7784 * Parse a Literal
7785 *
7786 * [29] Literal ::= '"' [^"]* '"'
7787 * | "'" [^']* "'"
7788 *
7789 * Returns the value found or NULL in case of error
7790 */
7791static xmlChar *
7792xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7793 const xmlChar *q;
7794 xmlChar *ret = NULL;
7795
7796 if (CUR == '"') {
7797 NEXT;
7798 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007799 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007800 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007801 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007802 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7803 } else {
7804 ret = xmlStrndup(q, CUR_PTR - q);
7805 NEXT;
7806 }
7807 } else if (CUR == '\'') {
7808 NEXT;
7809 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007810 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007811 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007812 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007813 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7814 } else {
7815 ret = xmlStrndup(q, CUR_PTR - q);
7816 NEXT;
7817 }
7818 } else {
7819 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7820 }
7821 return(ret);
7822}
7823
7824/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007825 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007826 * @ctxt: the XPath Parser context
7827 *
7828 * Parse a Literal and push it on the stack.
7829 *
7830 * [29] Literal ::= '"' [^"]* '"'
7831 * | "'" [^']* "'"
7832 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007833 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007834 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007835static void
7836xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007837 const xmlChar *q;
7838 xmlChar *ret = NULL;
7839
7840 if (CUR == '"') {
7841 NEXT;
7842 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007843 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007844 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007845 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007846 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7847 } else {
7848 ret = xmlStrndup(q, CUR_PTR - q);
7849 NEXT;
7850 }
7851 } else if (CUR == '\'') {
7852 NEXT;
7853 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007854 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007855 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007856 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007857 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7858 } else {
7859 ret = xmlStrndup(q, CUR_PTR - q);
7860 NEXT;
7861 }
7862 } else {
7863 XP_ERROR(XPATH_START_LITERAL_ERROR);
7864 }
7865 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007866 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7867 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007868 xmlFree(ret);
7869}
7870
7871/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007872 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007873 * @ctxt: the XPath Parser context
7874 *
7875 * Parse a VariableReference, evaluate it and push it on the stack.
7876 *
7877 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00007878 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00007879 * of any of the types that are possible for the value of an expression,
7880 * and may also be of additional types not specified here.
7881 *
7882 * Early evaluation is possible since:
7883 * The variable bindings [...] used to evaluate a subexpression are
7884 * always the same as those used to evaluate the containing expression.
7885 *
7886 * [36] VariableReference ::= '$' QName
7887 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007888static void
7889xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007890 xmlChar *name;
7891 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007892
7893 SKIP_BLANKS;
7894 if (CUR != '$') {
7895 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7896 }
7897 NEXT;
7898 name = xmlXPathParseQName(ctxt, &prefix);
7899 if (name == NULL) {
7900 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7901 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007902 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007903 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7904 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007905 SKIP_BLANKS;
7906}
7907
7908/**
7909 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007910 * @name: a name string
7911 *
7912 * Is the name given a NodeType one.
7913 *
7914 * [38] NodeType ::= 'comment'
7915 * | 'text'
7916 * | 'processing-instruction'
7917 * | 'node'
7918 *
7919 * Returns 1 if true 0 otherwise
7920 */
7921int
7922xmlXPathIsNodeType(const xmlChar *name) {
7923 if (name == NULL)
7924 return(0);
7925
Daniel Veillard1971ee22002-01-31 20:29:19 +00007926 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007927 return(1);
7928 if (xmlStrEqual(name, BAD_CAST "text"))
7929 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007930 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007931 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007932 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007933 return(1);
7934 return(0);
7935}
7936
7937/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007938 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007939 * @ctxt: the XPath Parser context
7940 *
7941 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7942 * [17] Argument ::= Expr
7943 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007944 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007945 * pushed on the stack
7946 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007947static void
7948xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007949 xmlChar *name;
7950 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007951 int nbargs = 0;
7952
7953 name = xmlXPathParseQName(ctxt, &prefix);
7954 if (name == NULL) {
7955 XP_ERROR(XPATH_EXPR_ERROR);
7956 }
7957 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007958#ifdef DEBUG_EXPR
7959 if (prefix == NULL)
7960 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7961 name);
7962 else
7963 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7964 prefix, name);
7965#endif
7966
Owen Taylor3473f882001-02-23 17:55:21 +00007967 if (CUR != '(') {
7968 XP_ERROR(XPATH_EXPR_ERROR);
7969 }
7970 NEXT;
7971 SKIP_BLANKS;
7972
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007973 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007974 if (CUR != ')') {
7975 while (CUR != 0) {
7976 int op1 = ctxt->comp->last;
7977 ctxt->comp->last = -1;
7978 xmlXPathCompileExpr(ctxt);
7979 CHECK_ERROR;
7980 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7981 nbargs++;
7982 if (CUR == ')') break;
7983 if (CUR != ',') {
7984 XP_ERROR(XPATH_EXPR_ERROR);
7985 }
7986 NEXT;
7987 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007988 }
Owen Taylor3473f882001-02-23 17:55:21 +00007989 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007990 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7991 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007992 NEXT;
7993 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007994}
7995
7996/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007997 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007998 * @ctxt: the XPath Parser context
7999 *
8000 * [15] PrimaryExpr ::= VariableReference
8001 * | '(' Expr ')'
8002 * | Literal
8003 * | Number
8004 * | FunctionCall
8005 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008006 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008007 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008008static void
8009xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008010 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008011 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008012 else if (CUR == '(') {
8013 NEXT;
8014 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008015 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00008016 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00008017 if (CUR != ')') {
8018 XP_ERROR(XPATH_EXPR_ERROR);
8019 }
8020 NEXT;
8021 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008022 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008023 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008024 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008025 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008026 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008027 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008028 }
8029 SKIP_BLANKS;
8030}
8031
8032/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008033 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008034 * @ctxt: the XPath Parser context
8035 *
8036 * [20] FilterExpr ::= PrimaryExpr
8037 * | FilterExpr Predicate
8038 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008039 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008040 * Square brackets are used to filter expressions in the same way that
8041 * they are used in location paths. It is an error if the expression to
8042 * be filtered does not evaluate to a node-set. The context node list
8043 * used for evaluating the expression in square brackets is the node-set
8044 * to be filtered listed in document order.
8045 */
8046
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008047static void
8048xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8049 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008050 CHECK_ERROR;
8051 SKIP_BLANKS;
8052
8053 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008054 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00008055 SKIP_BLANKS;
8056 }
8057
8058
8059}
8060
8061/**
8062 * xmlXPathScanName:
8063 * @ctxt: the XPath Parser context
8064 *
8065 * Trickery: parse an XML name but without consuming the input flow
8066 * Needed to avoid insanity in the parser state.
8067 *
8068 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8069 * CombiningChar | Extender
8070 *
8071 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8072 *
8073 * [6] Names ::= Name (S Name)*
8074 *
8075 * Returns the Name parsed or NULL
8076 */
8077
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008078static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00008079xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +00008080 int len = 0, l;
8081 int c;
Daniel Veillard03226812004-11-01 14:55:21 +00008082 const xmlChar *cur;
8083 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00008084
Daniel Veillard03226812004-11-01 14:55:21 +00008085 cur = ctxt->cur;
8086
8087 c = CUR_CHAR(l);
8088 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8089 (!IS_LETTER(c) && (c != '_') &&
8090 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008091 return(NULL);
8092 }
8093
Daniel Veillard03226812004-11-01 14:55:21 +00008094 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8095 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8096 (c == '.') || (c == '-') ||
8097 (c == '_') || (c == ':') ||
8098 (IS_COMBINING(c)) ||
8099 (IS_EXTENDER(c)))) {
8100 len += l;
8101 NEXTL(l);
8102 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +00008103 }
Daniel Veillard03226812004-11-01 14:55:21 +00008104 ret = xmlStrndup(cur, ctxt->cur - cur);
8105 ctxt->cur = cur;
8106 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00008107}
8108
8109/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008110 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008111 * @ctxt: the XPath Parser context
8112 *
8113 * [19] PathExpr ::= LocationPath
8114 * | FilterExpr
8115 * | FilterExpr '/' RelativeLocationPath
8116 * | FilterExpr '//' RelativeLocationPath
8117 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008118 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008119 * The / operator and // operators combine an arbitrary expression
8120 * and a relative location path. It is an error if the expression
8121 * does not evaluate to a node-set.
8122 * The / operator does composition in the same way as when / is
8123 * used in a location path. As in location paths, // is short for
8124 * /descendant-or-self::node()/.
8125 */
8126
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008127static void
8128xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008129 int lc = 1; /* Should we branch to LocationPath ? */
8130 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8131
8132 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008133 if ((CUR == '$') || (CUR == '(') ||
8134 (IS_ASCII_DIGIT(CUR)) ||
8135 (CUR == '\'') || (CUR == '"') ||
8136 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008137 lc = 0;
8138 } else if (CUR == '*') {
8139 /* relative or absolute location path */
8140 lc = 1;
8141 } else if (CUR == '/') {
8142 /* relative or absolute location path */
8143 lc = 1;
8144 } else if (CUR == '@') {
8145 /* relative abbreviated attribute location path */
8146 lc = 1;
8147 } else if (CUR == '.') {
8148 /* relative abbreviated attribute location path */
8149 lc = 1;
8150 } else {
8151 /*
8152 * Problem is finding if we have a name here whether it's:
8153 * - a nodetype
8154 * - a function call in which case it's followed by '('
8155 * - an axis in which case it's followed by ':'
8156 * - a element name
8157 * We do an a priori analysis here rather than having to
8158 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008159 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008160 * read/write/debug.
8161 */
8162 SKIP_BLANKS;
8163 name = xmlXPathScanName(ctxt);
8164 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8165#ifdef DEBUG_STEP
8166 xmlGenericError(xmlGenericErrorContext,
8167 "PathExpr: Axis\n");
8168#endif
8169 lc = 1;
8170 xmlFree(name);
8171 } else if (name != NULL) {
8172 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008173
8174
8175 while (NXT(len) != 0) {
8176 if (NXT(len) == '/') {
8177 /* element name */
8178#ifdef DEBUG_STEP
8179 xmlGenericError(xmlGenericErrorContext,
8180 "PathExpr: AbbrRelLocation\n");
8181#endif
8182 lc = 1;
8183 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008184 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008185 /* ignore blanks */
8186 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008187 } else if (NXT(len) == ':') {
8188#ifdef DEBUG_STEP
8189 xmlGenericError(xmlGenericErrorContext,
8190 "PathExpr: AbbrRelLocation\n");
8191#endif
8192 lc = 1;
8193 break;
8194 } else if ((NXT(len) == '(')) {
8195 /* Note Type or Function */
8196 if (xmlXPathIsNodeType(name)) {
8197#ifdef DEBUG_STEP
8198 xmlGenericError(xmlGenericErrorContext,
8199 "PathExpr: Type search\n");
8200#endif
8201 lc = 1;
8202 } else {
8203#ifdef DEBUG_STEP
8204 xmlGenericError(xmlGenericErrorContext,
8205 "PathExpr: function call\n");
8206#endif
8207 lc = 0;
8208 }
8209 break;
8210 } else if ((NXT(len) == '[')) {
8211 /* element name */
8212#ifdef DEBUG_STEP
8213 xmlGenericError(xmlGenericErrorContext,
8214 "PathExpr: AbbrRelLocation\n");
8215#endif
8216 lc = 1;
8217 break;
8218 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8219 (NXT(len) == '=')) {
8220 lc = 1;
8221 break;
8222 } else {
8223 lc = 1;
8224 break;
8225 }
8226 len++;
8227 }
8228 if (NXT(len) == 0) {
8229#ifdef DEBUG_STEP
8230 xmlGenericError(xmlGenericErrorContext,
8231 "PathExpr: AbbrRelLocation\n");
8232#endif
8233 /* element name */
8234 lc = 1;
8235 }
8236 xmlFree(name);
8237 } else {
William M. Brack08171912003-12-29 02:52:11 +00008238 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008239 XP_ERROR(XPATH_EXPR_ERROR);
8240 }
8241 }
8242
8243 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008244 if (CUR == '/') {
8245 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8246 } else {
8247 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008248 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008249 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008250 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008251 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008252 CHECK_ERROR;
8253 if ((CUR == '/') && (NXT(1) == '/')) {
8254 SKIP(2);
8255 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008256
8257 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8258 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8259 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8260
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008261 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008262 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008263 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008264 }
8265 }
8266 SKIP_BLANKS;
8267}
8268
8269/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008270 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008271 * @ctxt: the XPath Parser context
8272 *
8273 * [18] UnionExpr ::= PathExpr
8274 * | UnionExpr '|' PathExpr
8275 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008276 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008277 */
8278
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008279static void
8280xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8281 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008282 CHECK_ERROR;
8283 SKIP_BLANKS;
8284 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008285 int op1 = ctxt->comp->last;
8286 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008287
8288 NEXT;
8289 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008290 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008291
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008292 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8293
Owen Taylor3473f882001-02-23 17:55:21 +00008294 SKIP_BLANKS;
8295 }
Owen Taylor3473f882001-02-23 17:55:21 +00008296}
8297
8298/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008299 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008300 * @ctxt: the XPath Parser context
8301 *
8302 * [27] UnaryExpr ::= UnionExpr
8303 * | '-' UnaryExpr
8304 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008305 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008306 */
8307
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008308static void
8309xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008310 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008311 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008312
8313 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008314 while (CUR == '-') {
8315 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008316 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008317 NEXT;
8318 SKIP_BLANKS;
8319 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008320
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008321 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008322 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008323 if (found) {
8324 if (minus)
8325 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8326 else
8327 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008328 }
8329}
8330
8331/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008332 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008333 * @ctxt: the XPath Parser context
8334 *
8335 * [26] MultiplicativeExpr ::= UnaryExpr
8336 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8337 * | MultiplicativeExpr 'div' UnaryExpr
8338 * | MultiplicativeExpr 'mod' UnaryExpr
8339 * [34] MultiplyOperator ::= '*'
8340 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008341 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008342 */
8343
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008344static void
8345xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8346 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008347 CHECK_ERROR;
8348 SKIP_BLANKS;
8349 while ((CUR == '*') ||
8350 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8351 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8352 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008353 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008354
8355 if (CUR == '*') {
8356 op = 0;
8357 NEXT;
8358 } else if (CUR == 'd') {
8359 op = 1;
8360 SKIP(3);
8361 } else if (CUR == 'm') {
8362 op = 2;
8363 SKIP(3);
8364 }
8365 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008366 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008367 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008368 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008369 SKIP_BLANKS;
8370 }
8371}
8372
8373/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008374 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008375 * @ctxt: the XPath Parser context
8376 *
8377 * [25] AdditiveExpr ::= MultiplicativeExpr
8378 * | AdditiveExpr '+' MultiplicativeExpr
8379 * | AdditiveExpr '-' MultiplicativeExpr
8380 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008381 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008382 */
8383
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008384static void
8385xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008386
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008387 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008388 CHECK_ERROR;
8389 SKIP_BLANKS;
8390 while ((CUR == '+') || (CUR == '-')) {
8391 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008392 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008393
8394 if (CUR == '+') plus = 1;
8395 else plus = 0;
8396 NEXT;
8397 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008398 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008399 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008400 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008401 SKIP_BLANKS;
8402 }
8403}
8404
8405/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008406 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008407 * @ctxt: the XPath Parser context
8408 *
8409 * [24] RelationalExpr ::= AdditiveExpr
8410 * | RelationalExpr '<' AdditiveExpr
8411 * | RelationalExpr '>' AdditiveExpr
8412 * | RelationalExpr '<=' AdditiveExpr
8413 * | RelationalExpr '>=' AdditiveExpr
8414 *
8415 * A <= B > C is allowed ? Answer from James, yes with
8416 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8417 * which is basically what got implemented.
8418 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008419 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008420 * on the stack
8421 */
8422
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008423static void
8424xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8425 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008426 CHECK_ERROR;
8427 SKIP_BLANKS;
8428 while ((CUR == '<') ||
8429 (CUR == '>') ||
8430 ((CUR == '<') && (NXT(1) == '=')) ||
8431 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008432 int inf, strict;
8433 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008434
8435 if (CUR == '<') inf = 1;
8436 else inf = 0;
8437 if (NXT(1) == '=') strict = 0;
8438 else strict = 1;
8439 NEXT;
8440 if (!strict) NEXT;
8441 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008442 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008443 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008444 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008445 SKIP_BLANKS;
8446 }
8447}
8448
8449/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008450 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008451 * @ctxt: the XPath Parser context
8452 *
8453 * [23] EqualityExpr ::= RelationalExpr
8454 * | EqualityExpr '=' RelationalExpr
8455 * | EqualityExpr '!=' RelationalExpr
8456 *
8457 * A != B != C is allowed ? Answer from James, yes with
8458 * (RelationalExpr = RelationalExpr) = RelationalExpr
8459 * (RelationalExpr != RelationalExpr) != RelationalExpr
8460 * which is basically what got implemented.
8461 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008462 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008463 *
8464 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008465static void
8466xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8467 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008468 CHECK_ERROR;
8469 SKIP_BLANKS;
8470 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008471 int eq;
8472 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008473
8474 if (CUR == '=') eq = 1;
8475 else eq = 0;
8476 NEXT;
8477 if (!eq) NEXT;
8478 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008479 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008480 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008481 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008482 SKIP_BLANKS;
8483 }
8484}
8485
8486/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008487 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008488 * @ctxt: the XPath Parser context
8489 *
8490 * [22] AndExpr ::= EqualityExpr
8491 * | AndExpr 'and' EqualityExpr
8492 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008493 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008494 *
8495 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008496static void
8497xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8498 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008499 CHECK_ERROR;
8500 SKIP_BLANKS;
8501 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008502 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008503 SKIP(3);
8504 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008505 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008506 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008507 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008508 SKIP_BLANKS;
8509 }
8510}
8511
8512/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008513 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008514 * @ctxt: the XPath Parser context
8515 *
8516 * [14] Expr ::= OrExpr
8517 * [21] OrExpr ::= AndExpr
8518 * | OrExpr 'or' AndExpr
8519 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008520 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008521 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008522static void
8523xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8524 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008525 CHECK_ERROR;
8526 SKIP_BLANKS;
8527 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008528 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008529 SKIP(2);
8530 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008531 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008532 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008533 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8534 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008535 SKIP_BLANKS;
8536 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008537 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8538 /* more ops could be optimized too */
8539 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8540 }
Owen Taylor3473f882001-02-23 17:55:21 +00008541}
8542
8543/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008544 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008545 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008546 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008547 *
8548 * [8] Predicate ::= '[' PredicateExpr ']'
8549 * [9] PredicateExpr ::= Expr
8550 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008551 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008552 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008553static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008554xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008555 int op1 = ctxt->comp->last;
8556
8557 SKIP_BLANKS;
8558 if (CUR != '[') {
8559 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8560 }
8561 NEXT;
8562 SKIP_BLANKS;
8563
8564 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008565 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008566 CHECK_ERROR;
8567
8568 if (CUR != ']') {
8569 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8570 }
8571
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008572 if (filter)
8573 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8574 else
8575 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008576
8577 NEXT;
8578 SKIP_BLANKS;
8579}
8580
8581/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008582 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008583 * @ctxt: the XPath Parser context
8584 * @test: pointer to a xmlXPathTestVal
8585 * @type: pointer to a xmlXPathTypeVal
8586 * @prefix: placeholder for a possible name prefix
8587 *
8588 * [7] NodeTest ::= NameTest
8589 * | NodeType '(' ')'
8590 * | 'processing-instruction' '(' Literal ')'
8591 *
8592 * [37] NameTest ::= '*'
8593 * | NCName ':' '*'
8594 * | QName
8595 * [38] NodeType ::= 'comment'
8596 * | 'text'
8597 * | 'processing-instruction'
8598 * | 'node'
8599 *
William M. Brack08171912003-12-29 02:52:11 +00008600 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00008601 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008602static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008603xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8604 xmlXPathTypeVal *type, const xmlChar **prefix,
8605 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008606 int blanks;
8607
8608 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8609 STRANGE;
8610 return(NULL);
8611 }
William M. Brack78637da2003-07-31 14:47:38 +00008612 *type = (xmlXPathTypeVal) 0;
8613 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008614 *prefix = NULL;
8615 SKIP_BLANKS;
8616
8617 if ((name == NULL) && (CUR == '*')) {
8618 /*
8619 * All elements
8620 */
8621 NEXT;
8622 *test = NODE_TEST_ALL;
8623 return(NULL);
8624 }
8625
8626 if (name == NULL)
8627 name = xmlXPathParseNCName(ctxt);
8628 if (name == NULL) {
8629 XP_ERROR0(XPATH_EXPR_ERROR);
8630 }
8631
William M. Brack76e95df2003-10-18 16:20:14 +00008632 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008633 SKIP_BLANKS;
8634 if (CUR == '(') {
8635 NEXT;
8636 /*
8637 * NodeType or PI search
8638 */
8639 if (xmlStrEqual(name, BAD_CAST "comment"))
8640 *type = NODE_TYPE_COMMENT;
8641 else if (xmlStrEqual(name, BAD_CAST "node"))
8642 *type = NODE_TYPE_NODE;
8643 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8644 *type = NODE_TYPE_PI;
8645 else if (xmlStrEqual(name, BAD_CAST "text"))
8646 *type = NODE_TYPE_TEXT;
8647 else {
8648 if (name != NULL)
8649 xmlFree(name);
8650 XP_ERROR0(XPATH_EXPR_ERROR);
8651 }
8652
8653 *test = NODE_TEST_TYPE;
8654
8655 SKIP_BLANKS;
8656 if (*type == NODE_TYPE_PI) {
8657 /*
8658 * Specific case: search a PI by name.
8659 */
Owen Taylor3473f882001-02-23 17:55:21 +00008660 if (name != NULL)
8661 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008662 name = NULL;
8663 if (CUR != ')') {
8664 name = xmlXPathParseLiteral(ctxt);
8665 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008666 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008667 SKIP_BLANKS;
8668 }
Owen Taylor3473f882001-02-23 17:55:21 +00008669 }
8670 if (CUR != ')') {
8671 if (name != NULL)
8672 xmlFree(name);
8673 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8674 }
8675 NEXT;
8676 return(name);
8677 }
8678 *test = NODE_TEST_NAME;
8679 if ((!blanks) && (CUR == ':')) {
8680 NEXT;
8681
8682 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008683 * Since currently the parser context don't have a
8684 * namespace list associated:
8685 * The namespace name for this prefix can be computed
8686 * only at evaluation time. The compilation is done
8687 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008688 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008689#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008690 *prefix = xmlXPathNsLookup(ctxt->context, name);
8691 if (name != NULL)
8692 xmlFree(name);
8693 if (*prefix == NULL) {
8694 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8695 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008696#else
8697 *prefix = name;
8698#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008699
8700 if (CUR == '*') {
8701 /*
8702 * All elements
8703 */
8704 NEXT;
8705 *test = NODE_TEST_ALL;
8706 return(NULL);
8707 }
8708
8709 name = xmlXPathParseNCName(ctxt);
8710 if (name == NULL) {
8711 XP_ERROR0(XPATH_EXPR_ERROR);
8712 }
8713 }
8714 return(name);
8715}
8716
8717/**
8718 * xmlXPathIsAxisName:
8719 * @name: a preparsed name token
8720 *
8721 * [6] AxisName ::= 'ancestor'
8722 * | 'ancestor-or-self'
8723 * | 'attribute'
8724 * | 'child'
8725 * | 'descendant'
8726 * | 'descendant-or-self'
8727 * | 'following'
8728 * | 'following-sibling'
8729 * | 'namespace'
8730 * | 'parent'
8731 * | 'preceding'
8732 * | 'preceding-sibling'
8733 * | 'self'
8734 *
8735 * Returns the axis or 0
8736 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008737static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008738xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008739 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008740 switch (name[0]) {
8741 case 'a':
8742 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8743 ret = AXIS_ANCESTOR;
8744 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8745 ret = AXIS_ANCESTOR_OR_SELF;
8746 if (xmlStrEqual(name, BAD_CAST "attribute"))
8747 ret = AXIS_ATTRIBUTE;
8748 break;
8749 case 'c':
8750 if (xmlStrEqual(name, BAD_CAST "child"))
8751 ret = AXIS_CHILD;
8752 break;
8753 case 'd':
8754 if (xmlStrEqual(name, BAD_CAST "descendant"))
8755 ret = AXIS_DESCENDANT;
8756 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8757 ret = AXIS_DESCENDANT_OR_SELF;
8758 break;
8759 case 'f':
8760 if (xmlStrEqual(name, BAD_CAST "following"))
8761 ret = AXIS_FOLLOWING;
8762 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8763 ret = AXIS_FOLLOWING_SIBLING;
8764 break;
8765 case 'n':
8766 if (xmlStrEqual(name, BAD_CAST "namespace"))
8767 ret = AXIS_NAMESPACE;
8768 break;
8769 case 'p':
8770 if (xmlStrEqual(name, BAD_CAST "parent"))
8771 ret = AXIS_PARENT;
8772 if (xmlStrEqual(name, BAD_CAST "preceding"))
8773 ret = AXIS_PRECEDING;
8774 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8775 ret = AXIS_PRECEDING_SIBLING;
8776 break;
8777 case 's':
8778 if (xmlStrEqual(name, BAD_CAST "self"))
8779 ret = AXIS_SELF;
8780 break;
8781 }
8782 return(ret);
8783}
8784
8785/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008786 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008787 * @ctxt: the XPath Parser context
8788 *
8789 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8790 * | AbbreviatedStep
8791 *
8792 * [12] AbbreviatedStep ::= '.' | '..'
8793 *
8794 * [5] AxisSpecifier ::= AxisName '::'
8795 * | AbbreviatedAxisSpecifier
8796 *
8797 * [13] AbbreviatedAxisSpecifier ::= '@'?
8798 *
8799 * Modified for XPtr range support as:
8800 *
8801 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8802 * | AbbreviatedStep
8803 * | 'range-to' '(' Expr ')' Predicate*
8804 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008805 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008806 * A location step of . is short for self::node(). This is
8807 * particularly useful in conjunction with //. For example, the
8808 * location path .//para is short for
8809 * self::node()/descendant-or-self::node()/child::para
8810 * and so will select all para descendant elements of the context
8811 * node.
8812 * Similarly, a location step of .. is short for parent::node().
8813 * For example, ../title is short for parent::node()/child::title
8814 * and so will select the title children of the parent of the context
8815 * node.
8816 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008817static void
8818xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008819#ifdef LIBXML_XPTR_ENABLED
8820 int rangeto = 0;
8821 int op2 = -1;
8822#endif
8823
Owen Taylor3473f882001-02-23 17:55:21 +00008824 SKIP_BLANKS;
8825 if ((CUR == '.') && (NXT(1) == '.')) {
8826 SKIP(2);
8827 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008828 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8829 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008830 } else if (CUR == '.') {
8831 NEXT;
8832 SKIP_BLANKS;
8833 } else {
8834 xmlChar *name = NULL;
8835 const xmlChar *prefix = NULL;
8836 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008837 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008838 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008839 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008840
8841 /*
8842 * The modification needed for XPointer change to the production
8843 */
8844#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008845 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008846 name = xmlXPathParseNCName(ctxt);
8847 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008848 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008849 xmlFree(name);
8850 SKIP_BLANKS;
8851 if (CUR != '(') {
8852 XP_ERROR(XPATH_EXPR_ERROR);
8853 }
8854 NEXT;
8855 SKIP_BLANKS;
8856
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008857 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008858 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008859 CHECK_ERROR;
8860
8861 SKIP_BLANKS;
8862 if (CUR != ')') {
8863 XP_ERROR(XPATH_EXPR_ERROR);
8864 }
8865 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008866 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008867 goto eval_predicates;
8868 }
8869 }
8870#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008871 if (CUR == '*') {
8872 axis = AXIS_CHILD;
8873 } else {
8874 if (name == NULL)
8875 name = xmlXPathParseNCName(ctxt);
8876 if (name != NULL) {
8877 axis = xmlXPathIsAxisName(name);
8878 if (axis != 0) {
8879 SKIP_BLANKS;
8880 if ((CUR == ':') && (NXT(1) == ':')) {
8881 SKIP(2);
8882 xmlFree(name);
8883 name = NULL;
8884 } else {
8885 /* an element name can conflict with an axis one :-\ */
8886 axis = AXIS_CHILD;
8887 }
Owen Taylor3473f882001-02-23 17:55:21 +00008888 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008889 axis = AXIS_CHILD;
8890 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008891 } else if (CUR == '@') {
8892 NEXT;
8893 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008894 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008895 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008896 }
Owen Taylor3473f882001-02-23 17:55:21 +00008897 }
8898
8899 CHECK_ERROR;
8900
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008901 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008902 if (test == 0)
8903 return;
8904
8905#ifdef DEBUG_STEP
8906 xmlGenericError(xmlGenericErrorContext,
8907 "Basis : computing new set\n");
8908#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008909
Owen Taylor3473f882001-02-23 17:55:21 +00008910#ifdef DEBUG_STEP
8911 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008912 if (ctxt->value == NULL)
8913 xmlGenericError(xmlGenericErrorContext, "no value\n");
8914 else if (ctxt->value->nodesetval == NULL)
8915 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8916 else
8917 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008918#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008919
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008920#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008921eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008922#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008923 op1 = ctxt->comp->last;
8924 ctxt->comp->last = -1;
8925
Owen Taylor3473f882001-02-23 17:55:21 +00008926 SKIP_BLANKS;
8927 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008928 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008929 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008930
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008931#ifdef LIBXML_XPTR_ENABLED
8932 if (rangeto) {
8933 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8934 } else
8935#endif
8936 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8937 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008938
Owen Taylor3473f882001-02-23 17:55:21 +00008939 }
8940#ifdef DEBUG_STEP
8941 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008942 if (ctxt->value == NULL)
8943 xmlGenericError(xmlGenericErrorContext, "no value\n");
8944 else if (ctxt->value->nodesetval == NULL)
8945 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8946 else
8947 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8948 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008949#endif
8950}
8951
8952/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008953 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008954 * @ctxt: the XPath Parser context
8955 *
8956 * [3] RelativeLocationPath ::= Step
8957 * | RelativeLocationPath '/' Step
8958 * | AbbreviatedRelativeLocationPath
8959 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8960 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008961 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008962 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008963static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008964xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008965(xmlXPathParserContextPtr ctxt) {
8966 SKIP_BLANKS;
8967 if ((CUR == '/') && (NXT(1) == '/')) {
8968 SKIP(2);
8969 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008970 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8971 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008972 } else if (CUR == '/') {
8973 NEXT;
8974 SKIP_BLANKS;
8975 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008976 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008977 SKIP_BLANKS;
8978 while (CUR == '/') {
8979 if ((CUR == '/') && (NXT(1) == '/')) {
8980 SKIP(2);
8981 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008982 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008983 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008984 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008985 } else if (CUR == '/') {
8986 NEXT;
8987 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008988 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008989 }
8990 SKIP_BLANKS;
8991 }
8992}
8993
8994/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008995 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008996 * @ctxt: the XPath Parser context
8997 *
8998 * [1] LocationPath ::= RelativeLocationPath
8999 * | AbsoluteLocationPath
9000 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
9001 * | AbbreviatedAbsoluteLocationPath
9002 * [10] AbbreviatedAbsoluteLocationPath ::=
9003 * '//' RelativeLocationPath
9004 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009005 * Compile a location path
9006 *
Owen Taylor3473f882001-02-23 17:55:21 +00009007 * // is short for /descendant-or-self::node()/. For example,
9008 * //para is short for /descendant-or-self::node()/child::para and
9009 * so will select any para element in the document (even a para element
9010 * that is a document element will be selected by //para since the
9011 * document element node is a child of the root node); div//para is
9012 * short for div/descendant-or-self::node()/child::para and so will
9013 * select all para descendants of div children.
9014 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009015static void
9016xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009017 SKIP_BLANKS;
9018 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009019 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009020 } else {
9021 while (CUR == '/') {
9022 if ((CUR == '/') && (NXT(1) == '/')) {
9023 SKIP(2);
9024 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009025 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9026 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009027 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009028 } else if (CUR == '/') {
9029 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00009030 SKIP_BLANKS;
9031 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +00009032 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00009033 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009034 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009035 }
9036 }
9037 }
9038}
9039
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009040/************************************************************************
9041 * *
9042 * XPath precompiled expression evaluation *
9043 * *
9044 ************************************************************************/
9045
Daniel Veillardf06307e2001-07-03 10:35:50 +00009046static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009047xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
9048
9049/**
9050 * xmlXPathNodeCollectAndTest:
9051 * @ctxt: the XPath Parser context
9052 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009053 * @first: pointer to the first element in document order
9054 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009055 *
9056 * This is the function implementing a step: based on the current list
9057 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009058 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009059 *
9060 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00009061 *
William M. Brack08171912003-12-29 02:52:11 +00009062 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009063 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009064static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009065xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009066 xmlXPathStepOpPtr op,
9067 xmlNodePtr * first, xmlNodePtr * last)
9068{
William M. Brack78637da2003-07-31 14:47:38 +00009069 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9070 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9071 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009072 const xmlChar *prefix = op->value4;
9073 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009074 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009075
9076#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009077 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009078#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009079 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009080 xmlNodeSetPtr ret, list;
9081 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009082 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00009083 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009084 xmlNodePtr cur = NULL;
9085 xmlXPathObjectPtr obj;
9086 xmlNodeSetPtr nodelist;
9087 xmlNodePtr tmp;
9088
Daniel Veillardf06307e2001-07-03 10:35:50 +00009089 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009090 obj = valuePop(ctxt);
9091 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009092 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009093 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009094 URI = xmlXPathNsLookup(ctxt->context, prefix);
9095 if (URI == NULL)
9096 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00009097 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009098#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009099 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009100#endif
9101 switch (axis) {
9102 case AXIS_ANCESTOR:
9103#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009104 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009105#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009106 first = NULL;
9107 next = xmlXPathNextAncestor;
9108 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009109 case AXIS_ANCESTOR_OR_SELF:
9110#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009111 xmlGenericError(xmlGenericErrorContext,
9112 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009113#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009114 first = NULL;
9115 next = xmlXPathNextAncestorOrSelf;
9116 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009117 case AXIS_ATTRIBUTE:
9118#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009119 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009120#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009121 first = NULL;
9122 last = NULL;
9123 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009124 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009125 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009126 case AXIS_CHILD:
9127#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009128 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009129#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009130 last = NULL;
9131 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009132 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009133 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009134 case AXIS_DESCENDANT:
9135#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009136 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009137#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009138 last = NULL;
9139 next = xmlXPathNextDescendant;
9140 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009141 case AXIS_DESCENDANT_OR_SELF:
9142#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009143 xmlGenericError(xmlGenericErrorContext,
9144 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009145#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009146 last = NULL;
9147 next = xmlXPathNextDescendantOrSelf;
9148 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009149 case AXIS_FOLLOWING:
9150#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009151 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009152#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009153 last = NULL;
9154 next = xmlXPathNextFollowing;
9155 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009156 case AXIS_FOLLOWING_SIBLING:
9157#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009158 xmlGenericError(xmlGenericErrorContext,
9159 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009160#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009161 last = NULL;
9162 next = xmlXPathNextFollowingSibling;
9163 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009164 case AXIS_NAMESPACE:
9165#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009166 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009167#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009168 first = NULL;
9169 last = NULL;
9170 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009171 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009172 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009173 case AXIS_PARENT:
9174#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009175 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009176#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009177 first = NULL;
9178 next = xmlXPathNextParent;
9179 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009180 case AXIS_PRECEDING:
9181#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009182 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009183#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009184 first = NULL;
9185 next = xmlXPathNextPrecedingInternal;
9186 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009187 case AXIS_PRECEDING_SIBLING:
9188#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009189 xmlGenericError(xmlGenericErrorContext,
9190 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009191#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009192 first = NULL;
9193 next = xmlXPathNextPrecedingSibling;
9194 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009195 case AXIS_SELF:
9196#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009197 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009198#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009199 first = NULL;
9200 last = NULL;
9201 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009202 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009203 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009204 }
9205 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009206 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009207
9208 nodelist = obj->nodesetval;
9209 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009210 xmlXPathFreeObject(obj);
9211 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9212 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009213 }
9214 addNode = xmlXPathNodeSetAddUnique;
9215 ret = NULL;
9216#ifdef DEBUG_STEP
9217 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009218 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009219 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009220 case NODE_TEST_NONE:
9221 xmlGenericError(xmlGenericErrorContext,
9222 " searching for none !!!\n");
9223 break;
9224 case NODE_TEST_TYPE:
9225 xmlGenericError(xmlGenericErrorContext,
9226 " searching for type %d\n", type);
9227 break;
9228 case NODE_TEST_PI:
9229 xmlGenericError(xmlGenericErrorContext,
9230 " searching for PI !!!\n");
9231 break;
9232 case NODE_TEST_ALL:
9233 xmlGenericError(xmlGenericErrorContext,
9234 " searching for *\n");
9235 break;
9236 case NODE_TEST_NS:
9237 xmlGenericError(xmlGenericErrorContext,
9238 " searching for namespace %s\n",
9239 prefix);
9240 break;
9241 case NODE_TEST_NAME:
9242 xmlGenericError(xmlGenericErrorContext,
9243 " searching for name %s\n", name);
9244 if (prefix != NULL)
9245 xmlGenericError(xmlGenericErrorContext,
9246 " with namespace %s\n", prefix);
9247 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009248 }
9249 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9250#endif
9251 /*
9252 * 2.3 Node Tests
9253 * - For the attribute axis, the principal node type is attribute.
9254 * - For the namespace axis, the principal node type is namespace.
9255 * - For other axes, the principal node type is element.
9256 *
9257 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009258 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009259 * select all element children of the context node
9260 */
9261 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009262 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009263 ctxt->context->node = nodelist->nodeTab[i];
9264
Daniel Veillardf06307e2001-07-03 10:35:50 +00009265 cur = NULL;
9266 list = xmlXPathNodeSetCreate(NULL);
9267 do {
9268 cur = next(ctxt, cur);
9269 if (cur == NULL)
9270 break;
9271 if ((first != NULL) && (*first == cur))
9272 break;
9273 if (((t % 256) == 0) &&
9274 (first != NULL) && (*first != NULL) &&
9275 (xmlXPathCmpNodes(*first, cur) >= 0))
9276 break;
9277 if ((last != NULL) && (*last == cur))
9278 break;
9279 if (((t % 256) == 0) &&
9280 (last != NULL) && (*last != NULL) &&
9281 (xmlXPathCmpNodes(cur, *last) >= 0))
9282 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009283 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009284#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009285 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9286#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009287 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009288 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009289 ctxt->context->node = tmp;
9290 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009291 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009292 if ((cur->type == type) ||
9293 ((type == NODE_TYPE_NODE) &&
9294 ((cur->type == XML_DOCUMENT_NODE) ||
9295 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9296 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009297 (cur->type == XML_NAMESPACE_DECL) ||
9298 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009299 (cur->type == XML_PI_NODE) ||
9300 (cur->type == XML_COMMENT_NODE) ||
9301 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009302 (cur->type == XML_TEXT_NODE))) ||
9303 ((type == NODE_TYPE_TEXT) &&
9304 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009305#ifdef DEBUG_STEP
9306 n++;
9307#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009308 addNode(list, cur);
9309 }
9310 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009311 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009312 if (cur->type == XML_PI_NODE) {
9313 if ((name != NULL) &&
9314 (!xmlStrEqual(name, cur->name)))
9315 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009316#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009317 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009318#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009319 addNode(list, cur);
9320 }
9321 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009322 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009323 if (axis == AXIS_ATTRIBUTE) {
9324 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009325#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009326 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009327#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009328 addNode(list, cur);
9329 }
9330 } else if (axis == AXIS_NAMESPACE) {
9331 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009332#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009333 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009334#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009335 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9336 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009337 }
9338 } else {
9339 if (cur->type == XML_ELEMENT_NODE) {
9340 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009341#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009342 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009343#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009344 addNode(list, cur);
9345 } else if ((cur->ns != NULL) &&
9346 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009347#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009348 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009349#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009350 addNode(list, cur);
9351 }
9352 }
9353 }
9354 break;
9355 case NODE_TEST_NS:{
9356 TODO;
9357 break;
9358 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009359 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009360 switch (cur->type) {
9361 case XML_ELEMENT_NODE:
9362 if (xmlStrEqual(name, cur->name)) {
9363 if (prefix == NULL) {
9364 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009365#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009366 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009367#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009368 addNode(list, cur);
9369 }
9370 } else {
9371 if ((cur->ns != NULL) &&
9372 (xmlStrEqual(URI,
9373 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009374#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009375 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009376#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009377 addNode(list, cur);
9378 }
9379 }
9380 }
9381 break;
9382 case XML_ATTRIBUTE_NODE:{
9383 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009384
Daniel Veillardf06307e2001-07-03 10:35:50 +00009385 if (xmlStrEqual(name, attr->name)) {
9386 if (prefix == NULL) {
9387 if ((attr->ns == NULL) ||
9388 (attr->ns->prefix == NULL)) {
9389#ifdef DEBUG_STEP
9390 n++;
9391#endif
9392 addNode(list,
9393 (xmlNodePtr) attr);
9394 }
9395 } else {
9396 if ((attr->ns != NULL) &&
9397 (xmlStrEqual(URI,
9398 attr->ns->
9399 href))) {
9400#ifdef DEBUG_STEP
9401 n++;
9402#endif
9403 addNode(list,
9404 (xmlNodePtr) attr);
9405 }
9406 }
9407 }
9408 break;
9409 }
9410 case XML_NAMESPACE_DECL:
9411 if (cur->type == XML_NAMESPACE_DECL) {
9412 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009413
Daniel Veillardf06307e2001-07-03 10:35:50 +00009414 if ((ns->prefix != NULL) && (name != NULL)
9415 && (xmlStrEqual(ns->prefix, name))) {
9416#ifdef DEBUG_STEP
9417 n++;
9418#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009419 xmlXPathNodeSetAddNs(list,
9420 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009421 }
9422 }
9423 break;
9424 default:
9425 break;
9426 }
9427 break;
9428 break;
9429 }
9430 } while (cur != NULL);
9431
9432 /*
9433 * If there is some predicate filtering do it now
9434 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009435 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009436 xmlXPathObjectPtr obj2;
9437
9438 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9439 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9440 CHECK_TYPE0(XPATH_NODESET);
9441 obj2 = valuePop(ctxt);
9442 list = obj2->nodesetval;
9443 obj2->nodesetval = NULL;
9444 xmlXPathFreeObject(obj2);
9445 }
9446 if (ret == NULL) {
9447 ret = list;
9448 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009449 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009450 xmlXPathFreeNodeSet(list);
9451 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009452 }
9453 ctxt->context->node = tmp;
9454#ifdef DEBUG_STEP
9455 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009456 "\nExamined %d nodes, found %d nodes at that step\n",
9457 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009458#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009459 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009460 if ((obj->boolval) && (obj->user != NULL)) {
9461 ctxt->value->boolval = 1;
9462 ctxt->value->user = obj->user;
9463 obj->user = NULL;
9464 obj->boolval = 0;
9465 }
9466 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009467 return(t);
9468}
9469
9470/**
9471 * xmlXPathNodeCollectAndTestNth:
9472 * @ctxt: the XPath Parser context
9473 * @op: the XPath precompiled step operation
9474 * @indx: the index to collect
9475 * @first: pointer to the first element in document order
9476 * @last: pointer to the last element in document order
9477 *
9478 * This is the function implementing a step: based on the current list
9479 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009480 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009481 *
9482 * Pushes the new NodeSet resulting from the search.
9483 * Returns the number of node traversed
9484 */
9485static int
9486xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9487 xmlXPathStepOpPtr op, int indx,
9488 xmlNodePtr * first, xmlNodePtr * last)
9489{
William M. Brack78637da2003-07-31 14:47:38 +00009490 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9491 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9492 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009493 const xmlChar *prefix = op->value4;
9494 const xmlChar *name = op->value5;
9495 const xmlChar *URI = NULL;
9496 int n = 0, t = 0;
9497
9498 int i;
9499 xmlNodeSetPtr list;
9500 xmlXPathTraversalFunction next = NULL;
9501 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9502 xmlNodePtr cur = NULL;
9503 xmlXPathObjectPtr obj;
9504 xmlNodeSetPtr nodelist;
9505 xmlNodePtr tmp;
9506
9507 CHECK_TYPE0(XPATH_NODESET);
9508 obj = valuePop(ctxt);
9509 addNode = xmlXPathNodeSetAdd;
9510 if (prefix != NULL) {
9511 URI = xmlXPathNsLookup(ctxt->context, prefix);
9512 if (URI == NULL)
9513 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9514 }
9515#ifdef DEBUG_STEP_NTH
9516 xmlGenericError(xmlGenericErrorContext, "new step : ");
9517 if (first != NULL) {
9518 if (*first != NULL)
9519 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9520 (*first)->name);
9521 else
9522 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9523 }
9524 if (last != NULL) {
9525 if (*last != NULL)
9526 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9527 (*last)->name);
9528 else
9529 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9530 }
9531#endif
9532 switch (axis) {
9533 case AXIS_ANCESTOR:
9534#ifdef DEBUG_STEP_NTH
9535 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9536#endif
9537 first = NULL;
9538 next = xmlXPathNextAncestor;
9539 break;
9540 case AXIS_ANCESTOR_OR_SELF:
9541#ifdef DEBUG_STEP_NTH
9542 xmlGenericError(xmlGenericErrorContext,
9543 "axis 'ancestors-or-self' ");
9544#endif
9545 first = NULL;
9546 next = xmlXPathNextAncestorOrSelf;
9547 break;
9548 case AXIS_ATTRIBUTE:
9549#ifdef DEBUG_STEP_NTH
9550 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9551#endif
9552 first = NULL;
9553 last = NULL;
9554 next = xmlXPathNextAttribute;
9555 break;
9556 case AXIS_CHILD:
9557#ifdef DEBUG_STEP_NTH
9558 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9559#endif
9560 last = NULL;
9561 next = xmlXPathNextChild;
9562 break;
9563 case AXIS_DESCENDANT:
9564#ifdef DEBUG_STEP_NTH
9565 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9566#endif
9567 last = NULL;
9568 next = xmlXPathNextDescendant;
9569 break;
9570 case AXIS_DESCENDANT_OR_SELF:
9571#ifdef DEBUG_STEP_NTH
9572 xmlGenericError(xmlGenericErrorContext,
9573 "axis 'descendant-or-self' ");
9574#endif
9575 last = NULL;
9576 next = xmlXPathNextDescendantOrSelf;
9577 break;
9578 case AXIS_FOLLOWING:
9579#ifdef DEBUG_STEP_NTH
9580 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9581#endif
9582 last = NULL;
9583 next = xmlXPathNextFollowing;
9584 break;
9585 case AXIS_FOLLOWING_SIBLING:
9586#ifdef DEBUG_STEP_NTH
9587 xmlGenericError(xmlGenericErrorContext,
9588 "axis 'following-siblings' ");
9589#endif
9590 last = NULL;
9591 next = xmlXPathNextFollowingSibling;
9592 break;
9593 case AXIS_NAMESPACE:
9594#ifdef DEBUG_STEP_NTH
9595 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9596#endif
9597 last = NULL;
9598 first = NULL;
9599 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9600 break;
9601 case AXIS_PARENT:
9602#ifdef DEBUG_STEP_NTH
9603 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9604#endif
9605 first = NULL;
9606 next = xmlXPathNextParent;
9607 break;
9608 case AXIS_PRECEDING:
9609#ifdef DEBUG_STEP_NTH
9610 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9611#endif
9612 first = NULL;
9613 next = xmlXPathNextPrecedingInternal;
9614 break;
9615 case AXIS_PRECEDING_SIBLING:
9616#ifdef DEBUG_STEP_NTH
9617 xmlGenericError(xmlGenericErrorContext,
9618 "axis 'preceding-sibling' ");
9619#endif
9620 first = NULL;
9621 next = xmlXPathNextPrecedingSibling;
9622 break;
9623 case AXIS_SELF:
9624#ifdef DEBUG_STEP_NTH
9625 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9626#endif
9627 first = NULL;
9628 last = NULL;
9629 next = xmlXPathNextSelf;
9630 break;
9631 }
9632 if (next == NULL)
9633 return(0);
9634
9635 nodelist = obj->nodesetval;
9636 if (nodelist == NULL) {
9637 xmlXPathFreeObject(obj);
9638 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9639 return(0);
9640 }
9641 addNode = xmlXPathNodeSetAddUnique;
9642#ifdef DEBUG_STEP_NTH
9643 xmlGenericError(xmlGenericErrorContext,
9644 " context contains %d nodes\n", nodelist->nodeNr);
9645 switch (test) {
9646 case NODE_TEST_NONE:
9647 xmlGenericError(xmlGenericErrorContext,
9648 " searching for none !!!\n");
9649 break;
9650 case NODE_TEST_TYPE:
9651 xmlGenericError(xmlGenericErrorContext,
9652 " searching for type %d\n", type);
9653 break;
9654 case NODE_TEST_PI:
9655 xmlGenericError(xmlGenericErrorContext,
9656 " searching for PI !!!\n");
9657 break;
9658 case NODE_TEST_ALL:
9659 xmlGenericError(xmlGenericErrorContext,
9660 " searching for *\n");
9661 break;
9662 case NODE_TEST_NS:
9663 xmlGenericError(xmlGenericErrorContext,
9664 " searching for namespace %s\n",
9665 prefix);
9666 break;
9667 case NODE_TEST_NAME:
9668 xmlGenericError(xmlGenericErrorContext,
9669 " searching for name %s\n", name);
9670 if (prefix != NULL)
9671 xmlGenericError(xmlGenericErrorContext,
9672 " with namespace %s\n", prefix);
9673 break;
9674 }
9675 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9676#endif
9677 /*
9678 * 2.3 Node Tests
9679 * - For the attribute axis, the principal node type is attribute.
9680 * - For the namespace axis, the principal node type is namespace.
9681 * - For other axes, the principal node type is element.
9682 *
9683 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009684 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009685 * select all element children of the context node
9686 */
9687 tmp = ctxt->context->node;
9688 list = xmlXPathNodeSetCreate(NULL);
9689 for (i = 0; i < nodelist->nodeNr; i++) {
9690 ctxt->context->node = nodelist->nodeTab[i];
9691
9692 cur = NULL;
9693 n = 0;
9694 do {
9695 cur = next(ctxt, cur);
9696 if (cur == NULL)
9697 break;
9698 if ((first != NULL) && (*first == cur))
9699 break;
9700 if (((t % 256) == 0) &&
9701 (first != NULL) && (*first != NULL) &&
9702 (xmlXPathCmpNodes(*first, cur) >= 0))
9703 break;
9704 if ((last != NULL) && (*last == cur))
9705 break;
9706 if (((t % 256) == 0) &&
9707 (last != NULL) && (*last != NULL) &&
9708 (xmlXPathCmpNodes(cur, *last) >= 0))
9709 break;
9710 t++;
9711 switch (test) {
9712 case NODE_TEST_NONE:
9713 ctxt->context->node = tmp;
9714 STRANGE return(0);
9715 case NODE_TEST_TYPE:
9716 if ((cur->type == type) ||
9717 ((type == NODE_TYPE_NODE) &&
9718 ((cur->type == XML_DOCUMENT_NODE) ||
9719 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9720 (cur->type == XML_ELEMENT_NODE) ||
9721 (cur->type == XML_PI_NODE) ||
9722 (cur->type == XML_COMMENT_NODE) ||
9723 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009724 (cur->type == XML_TEXT_NODE))) ||
9725 ((type == NODE_TYPE_TEXT) &&
9726 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009727 n++;
9728 if (n == indx)
9729 addNode(list, cur);
9730 }
9731 break;
9732 case NODE_TEST_PI:
9733 if (cur->type == XML_PI_NODE) {
9734 if ((name != NULL) &&
9735 (!xmlStrEqual(name, cur->name)))
9736 break;
9737 n++;
9738 if (n == indx)
9739 addNode(list, cur);
9740 }
9741 break;
9742 case NODE_TEST_ALL:
9743 if (axis == AXIS_ATTRIBUTE) {
9744 if (cur->type == XML_ATTRIBUTE_NODE) {
9745 n++;
9746 if (n == indx)
9747 addNode(list, cur);
9748 }
9749 } else if (axis == AXIS_NAMESPACE) {
9750 if (cur->type == XML_NAMESPACE_DECL) {
9751 n++;
9752 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009753 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9754 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009755 }
9756 } else {
9757 if (cur->type == XML_ELEMENT_NODE) {
9758 if (prefix == NULL) {
9759 n++;
9760 if (n == indx)
9761 addNode(list, cur);
9762 } else if ((cur->ns != NULL) &&
9763 (xmlStrEqual(URI, cur->ns->href))) {
9764 n++;
9765 if (n == indx)
9766 addNode(list, cur);
9767 }
9768 }
9769 }
9770 break;
9771 case NODE_TEST_NS:{
9772 TODO;
9773 break;
9774 }
9775 case NODE_TEST_NAME:
9776 switch (cur->type) {
9777 case XML_ELEMENT_NODE:
9778 if (xmlStrEqual(name, cur->name)) {
9779 if (prefix == NULL) {
9780 if (cur->ns == NULL) {
9781 n++;
9782 if (n == indx)
9783 addNode(list, cur);
9784 }
9785 } else {
9786 if ((cur->ns != NULL) &&
9787 (xmlStrEqual(URI,
9788 cur->ns->href))) {
9789 n++;
9790 if (n == indx)
9791 addNode(list, cur);
9792 }
9793 }
9794 }
9795 break;
9796 case XML_ATTRIBUTE_NODE:{
9797 xmlAttrPtr attr = (xmlAttrPtr) cur;
9798
9799 if (xmlStrEqual(name, attr->name)) {
9800 if (prefix == NULL) {
9801 if ((attr->ns == NULL) ||
9802 (attr->ns->prefix == NULL)) {
9803 n++;
9804 if (n == indx)
9805 addNode(list, cur);
9806 }
9807 } else {
9808 if ((attr->ns != NULL) &&
9809 (xmlStrEqual(URI,
9810 attr->ns->
9811 href))) {
9812 n++;
9813 if (n == indx)
9814 addNode(list, cur);
9815 }
9816 }
9817 }
9818 break;
9819 }
9820 case XML_NAMESPACE_DECL:
9821 if (cur->type == XML_NAMESPACE_DECL) {
9822 xmlNsPtr ns = (xmlNsPtr) cur;
9823
9824 if ((ns->prefix != NULL) && (name != NULL)
9825 && (xmlStrEqual(ns->prefix, name))) {
9826 n++;
9827 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009828 xmlXPathNodeSetAddNs(list,
9829 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009830 }
9831 }
9832 break;
9833 default:
9834 break;
9835 }
9836 break;
9837 break;
9838 }
9839 } while (n < indx);
9840 }
9841 ctxt->context->node = tmp;
9842#ifdef DEBUG_STEP_NTH
9843 xmlGenericError(xmlGenericErrorContext,
9844 "\nExamined %d nodes, found %d nodes at that step\n",
9845 t, list->nodeNr);
9846#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009847 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009848 if ((obj->boolval) && (obj->user != NULL)) {
9849 ctxt->value->boolval = 1;
9850 ctxt->value->user = obj->user;
9851 obj->user = NULL;
9852 obj->boolval = 0;
9853 }
9854 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009855 return(t);
9856}
9857
9858/**
9859 * xmlXPathCompOpEvalFirst:
9860 * @ctxt: the XPath parser context with the compiled expression
9861 * @op: an XPath compiled operation
9862 * @first: the first elem found so far
9863 *
9864 * Evaluate the Precompiled XPath operation searching only the first
9865 * element in document order
9866 *
9867 * Returns the number of examined objects.
9868 */
9869static int
9870xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9871 xmlXPathStepOpPtr op, xmlNodePtr * first)
9872{
9873 int total = 0, cur;
9874 xmlXPathCompExprPtr comp;
9875 xmlXPathObjectPtr arg1, arg2;
9876
Daniel Veillard556c6682001-10-06 09:59:51 +00009877 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009878 comp = ctxt->comp;
9879 switch (op->op) {
9880 case XPATH_OP_END:
9881 return (0);
9882 case XPATH_OP_UNION:
9883 total =
9884 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9885 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009886 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009887 if ((ctxt->value != NULL)
9888 && (ctxt->value->type == XPATH_NODESET)
9889 && (ctxt->value->nodesetval != NULL)
9890 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9891 /*
9892 * limit tree traversing to first node in the result
9893 */
9894 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9895 *first = ctxt->value->nodesetval->nodeTab[0];
9896 }
9897 cur =
9898 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9899 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009900 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009901 CHECK_TYPE0(XPATH_NODESET);
9902 arg2 = valuePop(ctxt);
9903
9904 CHECK_TYPE0(XPATH_NODESET);
9905 arg1 = valuePop(ctxt);
9906
9907 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9908 arg2->nodesetval);
9909 valuePush(ctxt, arg1);
9910 xmlXPathFreeObject(arg2);
9911 /* optimizer */
9912 if (total > cur)
9913 xmlXPathCompSwap(op);
9914 return (total + cur);
9915 case XPATH_OP_ROOT:
9916 xmlXPathRoot(ctxt);
9917 return (0);
9918 case XPATH_OP_NODE:
9919 if (op->ch1 != -1)
9920 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009921 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009922 if (op->ch2 != -1)
9923 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009924 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009925 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9926 return (total);
9927 case XPATH_OP_RESET:
9928 if (op->ch1 != -1)
9929 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009930 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009931 if (op->ch2 != -1)
9932 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009933 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009934 ctxt->context->node = NULL;
9935 return (total);
9936 case XPATH_OP_COLLECT:{
9937 if (op->ch1 == -1)
9938 return (total);
9939
9940 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009941 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009942
9943 /*
9944 * Optimization for [n] selection where n is a number
9945 */
9946 if ((op->ch2 != -1) &&
9947 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9948 (comp->steps[op->ch2].ch1 == -1) &&
9949 (comp->steps[op->ch2].ch2 != -1) &&
9950 (comp->steps[comp->steps[op->ch2].ch2].op ==
9951 XPATH_OP_VALUE)) {
9952 xmlXPathObjectPtr val;
9953
9954 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9955 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9956 int indx = (int) val->floatval;
9957
9958 if (val->floatval == (float) indx) {
9959 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9960 first, NULL);
9961 return (total);
9962 }
9963 }
9964 }
9965 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9966 return (total);
9967 }
9968 case XPATH_OP_VALUE:
9969 valuePush(ctxt,
9970 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9971 return (0);
9972 case XPATH_OP_SORT:
9973 if (op->ch1 != -1)
9974 total +=
9975 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9976 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009977 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009978 if ((ctxt->value != NULL)
9979 && (ctxt->value->type == XPATH_NODESET)
9980 && (ctxt->value->nodesetval != NULL))
9981 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9982 return (total);
9983 default:
9984 return (xmlXPathCompOpEval(ctxt, op));
9985 }
9986}
9987
9988/**
9989 * xmlXPathCompOpEvalLast:
9990 * @ctxt: the XPath parser context with the compiled expression
9991 * @op: an XPath compiled operation
9992 * @last: the last elem found so far
9993 *
9994 * Evaluate the Precompiled XPath operation searching only the last
9995 * element in document order
9996 *
William M. Brack08171912003-12-29 02:52:11 +00009997 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +00009998 */
9999static int
10000xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
10001 xmlNodePtr * last)
10002{
10003 int total = 0, cur;
10004 xmlXPathCompExprPtr comp;
10005 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000010006 xmlNodePtr bak;
10007 xmlDocPtr bakd;
10008 int pp;
10009 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010010
Daniel Veillard556c6682001-10-06 09:59:51 +000010011 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010012 comp = ctxt->comp;
10013 switch (op->op) {
10014 case XPATH_OP_END:
10015 return (0);
10016 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000010017 bakd = ctxt->context->doc;
10018 bak = ctxt->context->node;
10019 pp = ctxt->context->proximityPosition;
10020 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010021 total =
10022 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010023 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010024 if ((ctxt->value != NULL)
10025 && (ctxt->value->type == XPATH_NODESET)
10026 && (ctxt->value->nodesetval != NULL)
10027 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10028 /*
10029 * limit tree traversing to first node in the result
10030 */
10031 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10032 *last =
10033 ctxt->value->nodesetval->nodeTab[ctxt->value->
10034 nodesetval->nodeNr -
10035 1];
10036 }
William M. Brackce4fc562004-01-22 02:47:18 +000010037 ctxt->context->doc = bakd;
10038 ctxt->context->node = bak;
10039 ctxt->context->proximityPosition = pp;
10040 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010041 cur =
10042 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010043 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010044 if ((ctxt->value != NULL)
10045 && (ctxt->value->type == XPATH_NODESET)
10046 && (ctxt->value->nodesetval != NULL)
10047 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10048 }
10049 CHECK_TYPE0(XPATH_NODESET);
10050 arg2 = valuePop(ctxt);
10051
10052 CHECK_TYPE0(XPATH_NODESET);
10053 arg1 = valuePop(ctxt);
10054
10055 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10056 arg2->nodesetval);
10057 valuePush(ctxt, arg1);
10058 xmlXPathFreeObject(arg2);
10059 /* optimizer */
10060 if (total > cur)
10061 xmlXPathCompSwap(op);
10062 return (total + cur);
10063 case XPATH_OP_ROOT:
10064 xmlXPathRoot(ctxt);
10065 return (0);
10066 case XPATH_OP_NODE:
10067 if (op->ch1 != -1)
10068 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010069 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010070 if (op->ch2 != -1)
10071 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010072 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010073 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10074 return (total);
10075 case XPATH_OP_RESET:
10076 if (op->ch1 != -1)
10077 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010078 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010079 if (op->ch2 != -1)
10080 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010081 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010082 ctxt->context->node = NULL;
10083 return (total);
10084 case XPATH_OP_COLLECT:{
10085 if (op->ch1 == -1)
10086 return (0);
10087
10088 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010089 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010090
10091 /*
10092 * Optimization for [n] selection where n is a number
10093 */
10094 if ((op->ch2 != -1) &&
10095 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10096 (comp->steps[op->ch2].ch1 == -1) &&
10097 (comp->steps[op->ch2].ch2 != -1) &&
10098 (comp->steps[comp->steps[op->ch2].ch2].op ==
10099 XPATH_OP_VALUE)) {
10100 xmlXPathObjectPtr val;
10101
10102 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10103 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10104 int indx = (int) val->floatval;
10105
10106 if (val->floatval == (float) indx) {
10107 total +=
10108 xmlXPathNodeCollectAndTestNth(ctxt, op,
10109 indx, NULL,
10110 last);
10111 return (total);
10112 }
10113 }
10114 }
10115 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10116 return (total);
10117 }
10118 case XPATH_OP_VALUE:
10119 valuePush(ctxt,
10120 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10121 return (0);
10122 case XPATH_OP_SORT:
10123 if (op->ch1 != -1)
10124 total +=
10125 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10126 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010127 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010128 if ((ctxt->value != NULL)
10129 && (ctxt->value->type == XPATH_NODESET)
10130 && (ctxt->value->nodesetval != NULL))
10131 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10132 return (total);
10133 default:
10134 return (xmlXPathCompOpEval(ctxt, op));
10135 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010136}
10137
Owen Taylor3473f882001-02-23 17:55:21 +000010138/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010139 * xmlXPathCompOpEval:
10140 * @ctxt: the XPath parser context with the compiled expression
10141 * @op: an XPath compiled operation
10142 *
10143 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010144 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010145 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010146static int
10147xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10148{
10149 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010150 int equal, ret;
10151 xmlXPathCompExprPtr comp;
10152 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010153 xmlNodePtr bak;
10154 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010155 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010156 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010157
Daniel Veillard556c6682001-10-06 09:59:51 +000010158 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010159 comp = ctxt->comp;
10160 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010161 case XPATH_OP_END:
10162 return (0);
10163 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010164 bakd = ctxt->context->doc;
10165 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010166 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010167 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010168 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010169 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010170 xmlXPathBooleanFunction(ctxt, 1);
10171 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10172 return (total);
10173 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010174 ctxt->context->doc = bakd;
10175 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010176 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010177 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010178 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010179 if (ctxt->error) {
10180 xmlXPathFreeObject(arg2);
10181 return(0);
10182 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010183 xmlXPathBooleanFunction(ctxt, 1);
10184 arg1 = valuePop(ctxt);
10185 arg1->boolval &= arg2->boolval;
10186 valuePush(ctxt, arg1);
10187 xmlXPathFreeObject(arg2);
10188 return (total);
10189 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010190 bakd = ctxt->context->doc;
10191 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010192 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010193 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010194 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010195 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010196 xmlXPathBooleanFunction(ctxt, 1);
10197 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10198 return (total);
10199 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010200 ctxt->context->doc = bakd;
10201 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010202 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010203 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010204 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010205 if (ctxt->error) {
10206 xmlXPathFreeObject(arg2);
10207 return(0);
10208 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010209 xmlXPathBooleanFunction(ctxt, 1);
10210 arg1 = valuePop(ctxt);
10211 arg1->boolval |= arg2->boolval;
10212 valuePush(ctxt, arg1);
10213 xmlXPathFreeObject(arg2);
10214 return (total);
10215 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010216 bakd = ctxt->context->doc;
10217 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010218 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010219 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010220 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010221 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010222 ctxt->context->doc = bakd;
10223 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010224 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010225 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010226 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010227 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010228 if (op->value)
10229 equal = xmlXPathEqualValues(ctxt);
10230 else
10231 equal = xmlXPathNotEqualValues(ctxt);
10232 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010233 return (total);
10234 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010235 bakd = ctxt->context->doc;
10236 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010237 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010238 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010239 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010240 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010241 ctxt->context->doc = bakd;
10242 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010243 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010244 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010245 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010246 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010247 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10248 valuePush(ctxt, xmlXPathNewBoolean(ret));
10249 return (total);
10250 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010251 bakd = ctxt->context->doc;
10252 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010253 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010254 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010255 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010256 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010257 if (op->ch2 != -1) {
10258 ctxt->context->doc = bakd;
10259 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010260 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010261 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010262 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010263 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010264 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010265 if (op->value == 0)
10266 xmlXPathSubValues(ctxt);
10267 else if (op->value == 1)
10268 xmlXPathAddValues(ctxt);
10269 else if (op->value == 2)
10270 xmlXPathValueFlipSign(ctxt);
10271 else if (op->value == 3) {
10272 CAST_TO_NUMBER;
10273 CHECK_TYPE0(XPATH_NUMBER);
10274 }
10275 return (total);
10276 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010277 bakd = ctxt->context->doc;
10278 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010279 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010280 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010281 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010282 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010283 ctxt->context->doc = bakd;
10284 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010285 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010286 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010287 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010288 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010289 if (op->value == 0)
10290 xmlXPathMultValues(ctxt);
10291 else if (op->value == 1)
10292 xmlXPathDivValues(ctxt);
10293 else if (op->value == 2)
10294 xmlXPathModValues(ctxt);
10295 return (total);
10296 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010297 bakd = ctxt->context->doc;
10298 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010299 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010300 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010301 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010302 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010303 ctxt->context->doc = bakd;
10304 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010305 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010306 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010307 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010308 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010309 CHECK_TYPE0(XPATH_NODESET);
10310 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010311
Daniel Veillardf06307e2001-07-03 10:35:50 +000010312 CHECK_TYPE0(XPATH_NODESET);
10313 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010314
Daniel Veillardf06307e2001-07-03 10:35:50 +000010315 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10316 arg2->nodesetval);
10317 valuePush(ctxt, arg1);
10318 xmlXPathFreeObject(arg2);
10319 return (total);
10320 case XPATH_OP_ROOT:
10321 xmlXPathRoot(ctxt);
10322 return (total);
10323 case XPATH_OP_NODE:
10324 if (op->ch1 != -1)
10325 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010326 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010327 if (op->ch2 != -1)
10328 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010329 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010330 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10331 return (total);
10332 case XPATH_OP_RESET:
10333 if (op->ch1 != -1)
10334 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010335 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010336 if (op->ch2 != -1)
10337 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010338 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010339 ctxt->context->node = NULL;
10340 return (total);
10341 case XPATH_OP_COLLECT:{
10342 if (op->ch1 == -1)
10343 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010344
Daniel Veillardf06307e2001-07-03 10:35:50 +000010345 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010346 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010347
Daniel Veillardf06307e2001-07-03 10:35:50 +000010348 /*
10349 * Optimization for [n] selection where n is a number
10350 */
10351 if ((op->ch2 != -1) &&
10352 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10353 (comp->steps[op->ch2].ch1 == -1) &&
10354 (comp->steps[op->ch2].ch2 != -1) &&
10355 (comp->steps[comp->steps[op->ch2].ch2].op ==
10356 XPATH_OP_VALUE)) {
10357 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010358
Daniel Veillardf06307e2001-07-03 10:35:50 +000010359 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10360 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10361 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010362
Daniel Veillardf06307e2001-07-03 10:35:50 +000010363 if (val->floatval == (float) indx) {
10364 total +=
10365 xmlXPathNodeCollectAndTestNth(ctxt, op,
10366 indx, NULL,
10367 NULL);
10368 return (total);
10369 }
10370 }
10371 }
10372 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10373 return (total);
10374 }
10375 case XPATH_OP_VALUE:
10376 valuePush(ctxt,
10377 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10378 return (total);
10379 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010380 xmlXPathObjectPtr val;
10381
Daniel Veillardf06307e2001-07-03 10:35:50 +000010382 if (op->ch1 != -1)
10383 total +=
10384 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010385 if (op->value5 == NULL) {
10386 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10387 if (val == NULL) {
10388 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10389 return(0);
10390 }
10391 valuePush(ctxt, val);
10392 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010393 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010394
Daniel Veillardf06307e2001-07-03 10:35:50 +000010395 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10396 if (URI == NULL) {
10397 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010398 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010399 op->value4, op->value5);
10400 return (total);
10401 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010402 val = xmlXPathVariableLookupNS(ctxt->context,
10403 op->value4, URI);
10404 if (val == NULL) {
10405 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10406 return(0);
10407 }
10408 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010409 }
10410 return (total);
10411 }
10412 case XPATH_OP_FUNCTION:{
10413 xmlXPathFunction func;
10414 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010415 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010416
10417 if (op->ch1 != -1)
10418 total +=
10419 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010420 if (ctxt->valueNr < op->value) {
10421 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010422 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010423 ctxt->error = XPATH_INVALID_OPERAND;
10424 return (total);
10425 }
10426 for (i = 0; i < op->value; i++)
10427 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10428 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010429 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010430 ctxt->error = XPATH_INVALID_OPERAND;
10431 return (total);
10432 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010433 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000010434 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010435 else {
10436 const xmlChar *URI = NULL;
10437
10438 if (op->value5 == NULL)
10439 func =
10440 xmlXPathFunctionLookup(ctxt->context,
10441 op->value4);
10442 else {
10443 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10444 if (URI == NULL) {
10445 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010446 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010447 op->value4, op->value5);
10448 return (total);
10449 }
10450 func = xmlXPathFunctionLookupNS(ctxt->context,
10451 op->value4, URI);
10452 }
10453 if (func == NULL) {
10454 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010455 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010456 op->value4);
10457 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010458 }
William M. Brackad0e67c2004-12-01 14:35:10 +000010459 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010460 op->cacheURI = (void *) URI;
10461 }
10462 oldFunc = ctxt->context->function;
10463 oldFuncURI = ctxt->context->functionURI;
10464 ctxt->context->function = op->value4;
10465 ctxt->context->functionURI = op->cacheURI;
10466 func(ctxt, op->value);
10467 ctxt->context->function = oldFunc;
10468 ctxt->context->functionURI = oldFuncURI;
10469 return (total);
10470 }
10471 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010472 bakd = ctxt->context->doc;
10473 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000010474 pp = ctxt->context->proximityPosition;
10475 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010476 if (op->ch1 != -1)
10477 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000010478 ctxt->context->contextSize = cs;
10479 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000010480 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000010481 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000010482 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010483 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010484 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010485 ctxt->context->doc = bakd;
10486 ctxt->context->node = bak;
10487 CHECK_ERROR0;
10488 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010489 return (total);
10490 case XPATH_OP_PREDICATE:
10491 case XPATH_OP_FILTER:{
10492 xmlXPathObjectPtr res;
10493 xmlXPathObjectPtr obj, tmp;
10494 xmlNodeSetPtr newset = NULL;
10495 xmlNodeSetPtr oldset;
10496 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000010497 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010498 int i;
10499
10500 /*
10501 * Optimization for ()[1] selection i.e. the first elem
10502 */
10503 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10504 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10505 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10506 xmlXPathObjectPtr val;
10507
10508 val = comp->steps[op->ch2].value4;
10509 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10510 (val->floatval == 1.0)) {
10511 xmlNodePtr first = NULL;
10512
10513 total +=
10514 xmlXPathCompOpEvalFirst(ctxt,
10515 &comp->steps[op->ch1],
10516 &first);
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 first value
10521 */
10522 if ((ctxt->value != NULL) &&
10523 (ctxt->value->type == XPATH_NODESET) &&
10524 (ctxt->value->nodesetval != NULL) &&
10525 (ctxt->value->nodesetval->nodeNr > 1))
10526 ctxt->value->nodesetval->nodeNr = 1;
10527 return (total);
10528 }
10529 }
10530 /*
10531 * Optimization for ()[last()] selection i.e. the last elem
10532 */
10533 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10534 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10535 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10536 int f = comp->steps[op->ch2].ch1;
10537
10538 if ((f != -1) &&
10539 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10540 (comp->steps[f].value5 == NULL) &&
10541 (comp->steps[f].value == 0) &&
10542 (comp->steps[f].value4 != NULL) &&
10543 (xmlStrEqual
10544 (comp->steps[f].value4, BAD_CAST "last"))) {
10545 xmlNodePtr last = NULL;
10546
10547 total +=
10548 xmlXPathCompOpEvalLast(ctxt,
10549 &comp->steps[op->ch1],
10550 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010551 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010552 /*
10553 * The nodeset should be in document order,
10554 * Keep only the last value
10555 */
10556 if ((ctxt->value != NULL) &&
10557 (ctxt->value->type == XPATH_NODESET) &&
10558 (ctxt->value->nodesetval != NULL) &&
10559 (ctxt->value->nodesetval->nodeTab != NULL) &&
10560 (ctxt->value->nodesetval->nodeNr > 1)) {
10561 ctxt->value->nodesetval->nodeTab[0] =
10562 ctxt->value->nodesetval->nodeTab[ctxt->
10563 value->
10564 nodesetval->
10565 nodeNr -
10566 1];
10567 ctxt->value->nodesetval->nodeNr = 1;
10568 }
10569 return (total);
10570 }
10571 }
10572
10573 if (op->ch1 != -1)
10574 total +=
10575 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010576 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010577 if (op->ch2 == -1)
10578 return (total);
10579 if (ctxt->value == NULL)
10580 return (total);
10581
10582 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010583
10584#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010585 /*
10586 * Hum are we filtering the result of an XPointer expression
10587 */
10588 if (ctxt->value->type == XPATH_LOCATIONSET) {
10589 xmlLocationSetPtr newlocset = NULL;
10590 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010591
Daniel Veillardf06307e2001-07-03 10:35:50 +000010592 /*
10593 * Extract the old locset, and then evaluate the result of the
10594 * expression for all the element in the locset. use it to grow
10595 * up a new locset.
10596 */
10597 CHECK_TYPE0(XPATH_LOCATIONSET);
10598 obj = valuePop(ctxt);
10599 oldlocset = obj->user;
10600 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010601
Daniel Veillardf06307e2001-07-03 10:35:50 +000010602 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10603 ctxt->context->contextSize = 0;
10604 ctxt->context->proximityPosition = 0;
10605 if (op->ch2 != -1)
10606 total +=
10607 xmlXPathCompOpEval(ctxt,
10608 &comp->steps[op->ch2]);
10609 res = valuePop(ctxt);
10610 if (res != NULL)
10611 xmlXPathFreeObject(res);
10612 valuePush(ctxt, obj);
10613 CHECK_ERROR0;
10614 return (total);
10615 }
10616 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010617
Daniel Veillardf06307e2001-07-03 10:35:50 +000010618 for (i = 0; i < oldlocset->locNr; i++) {
10619 /*
10620 * Run the evaluation with a node list made of a
10621 * single item in the nodelocset.
10622 */
10623 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010624 ctxt->context->contextSize = oldlocset->locNr;
10625 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010626 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10627 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010628
Daniel Veillardf06307e2001-07-03 10:35:50 +000010629 if (op->ch2 != -1)
10630 total +=
10631 xmlXPathCompOpEval(ctxt,
10632 &comp->steps[op->ch2]);
10633 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010634
Daniel Veillardf06307e2001-07-03 10:35:50 +000010635 /*
10636 * The result of the evaluation need to be tested to
10637 * decided whether the filter succeeded or not
10638 */
10639 res = valuePop(ctxt);
10640 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10641 xmlXPtrLocationSetAdd(newlocset,
10642 xmlXPathObjectCopy
10643 (oldlocset->locTab[i]));
10644 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010645
Daniel Veillardf06307e2001-07-03 10:35:50 +000010646 /*
10647 * Cleanup
10648 */
10649 if (res != NULL)
10650 xmlXPathFreeObject(res);
10651 if (ctxt->value == tmp) {
10652 res = valuePop(ctxt);
10653 xmlXPathFreeObject(res);
10654 }
10655
10656 ctxt->context->node = NULL;
10657 }
10658
10659 /*
10660 * The result is used as the new evaluation locset.
10661 */
10662 xmlXPathFreeObject(obj);
10663 ctxt->context->node = NULL;
10664 ctxt->context->contextSize = -1;
10665 ctxt->context->proximityPosition = -1;
10666 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10667 ctxt->context->node = oldnode;
10668 return (total);
10669 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010670#endif /* LIBXML_XPTR_ENABLED */
10671
Daniel Veillardf06307e2001-07-03 10:35:50 +000010672 /*
10673 * Extract the old set, and then evaluate the result of the
10674 * expression for all the element in the set. use it to grow
10675 * up a new set.
10676 */
10677 CHECK_TYPE0(XPATH_NODESET);
10678 obj = valuePop(ctxt);
10679 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010680
Daniel Veillardf06307e2001-07-03 10:35:50 +000010681 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000010682 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010683 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010684
Daniel Veillardf06307e2001-07-03 10:35:50 +000010685 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10686 ctxt->context->contextSize = 0;
10687 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000010688/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000010689 if (op->ch2 != -1)
10690 total +=
10691 xmlXPathCompOpEval(ctxt,
10692 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010693 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010694 res = valuePop(ctxt);
10695 if (res != NULL)
10696 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000010697*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000010698 valuePush(ctxt, obj);
10699 ctxt->context->node = oldnode;
10700 CHECK_ERROR0;
10701 } else {
10702 /*
10703 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000010704 * Also set the xpath document in case things like
10705 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000010706 */
10707 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010708
Daniel Veillardf06307e2001-07-03 10:35:50 +000010709 for (i = 0; i < oldset->nodeNr; i++) {
10710 /*
10711 * Run the evaluation with a node list made of
10712 * a single item in the nodeset.
10713 */
10714 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000010715 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
10716 (oldset->nodeTab[i]->doc != NULL))
10717 ctxt->context->doc = oldset->nodeTab[i]->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010718 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10719 valuePush(ctxt, tmp);
10720 ctxt->context->contextSize = oldset->nodeNr;
10721 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010722
Daniel Veillardf06307e2001-07-03 10:35:50 +000010723 if (op->ch2 != -1)
10724 total +=
10725 xmlXPathCompOpEval(ctxt,
10726 &comp->steps[op->ch2]);
10727 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010728
Daniel Veillardf06307e2001-07-03 10:35:50 +000010729 /*
William M. Brack08171912003-12-29 02:52:11 +000010730 * The result of the evaluation needs to be tested to
10731 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010732 */
10733 res = valuePop(ctxt);
10734 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10735 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10736 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010737
Daniel Veillardf06307e2001-07-03 10:35:50 +000010738 /*
10739 * Cleanup
10740 */
10741 if (res != NULL)
10742 xmlXPathFreeObject(res);
10743 if (ctxt->value == tmp) {
10744 res = valuePop(ctxt);
10745 xmlXPathFreeObject(res);
10746 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010747
Daniel Veillardf06307e2001-07-03 10:35:50 +000010748 ctxt->context->node = NULL;
10749 }
10750
10751 /*
10752 * The result is used as the new evaluation set.
10753 */
10754 xmlXPathFreeObject(obj);
10755 ctxt->context->node = NULL;
10756 ctxt->context->contextSize = -1;
10757 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000010758 /* may want to move this past the '}' later */
10759 ctxt->context->doc = oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010760 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10761 }
10762 ctxt->context->node = oldnode;
10763 return (total);
10764 }
10765 case XPATH_OP_SORT:
10766 if (op->ch1 != -1)
10767 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010768 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010769 if ((ctxt->value != NULL) &&
10770 (ctxt->value->type == XPATH_NODESET) &&
10771 (ctxt->value->nodesetval != NULL))
10772 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10773 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010774#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010775 case XPATH_OP_RANGETO:{
10776 xmlXPathObjectPtr range;
10777 xmlXPathObjectPtr res, obj;
10778 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010779 xmlLocationSetPtr newlocset = NULL;
10780 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010781 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000010782 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010783
Daniel Veillardf06307e2001-07-03 10:35:50 +000010784 if (op->ch1 != -1)
10785 total +=
10786 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10787 if (op->ch2 == -1)
10788 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010789
William M. Brack08171912003-12-29 02:52:11 +000010790 if (ctxt->value->type == XPATH_LOCATIONSET) {
10791 /*
10792 * Extract the old locset, and then evaluate the result of the
10793 * expression for all the element in the locset. use it to grow
10794 * up a new locset.
10795 */
10796 CHECK_TYPE0(XPATH_LOCATIONSET);
10797 obj = valuePop(ctxt);
10798 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010799
William M. Brack08171912003-12-29 02:52:11 +000010800 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000010801 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000010802 ctxt->context->contextSize = 0;
10803 ctxt->context->proximityPosition = 0;
10804 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10805 res = valuePop(ctxt);
10806 if (res != NULL)
10807 xmlXPathFreeObject(res);
10808 valuePush(ctxt, obj);
10809 CHECK_ERROR0;
10810 return (total);
10811 }
10812 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010813
William M. Brack08171912003-12-29 02:52:11 +000010814 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010815 /*
William M. Brack08171912003-12-29 02:52:11 +000010816 * Run the evaluation with a node list made of a
10817 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010818 */
William M. Brackf7eb7942003-12-31 07:59:17 +000010819 ctxt->context->node = oldlocset->locTab[i]->user;
10820 ctxt->context->contextSize = oldlocset->locNr;
10821 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010822 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10823 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010824
Daniel Veillardf06307e2001-07-03 10:35:50 +000010825 if (op->ch2 != -1)
10826 total +=
10827 xmlXPathCompOpEval(ctxt,
10828 &comp->steps[op->ch2]);
10829 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010830
Daniel Veillardf06307e2001-07-03 10:35:50 +000010831 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000010832 if (res->type == XPATH_LOCATIONSET) {
10833 xmlLocationSetPtr rloc =
10834 (xmlLocationSetPtr)res->user;
10835 for (j=0; j<rloc->locNr; j++) {
10836 range = xmlXPtrNewRange(
10837 oldlocset->locTab[i]->user,
10838 oldlocset->locTab[i]->index,
10839 rloc->locTab[j]->user2,
10840 rloc->locTab[j]->index2);
10841 if (range != NULL) {
10842 xmlXPtrLocationSetAdd(newlocset, range);
10843 }
10844 }
10845 } else {
10846 range = xmlXPtrNewRangeNodeObject(
10847 (xmlNodePtr)oldlocset->locTab[i]->user, res);
10848 if (range != NULL) {
10849 xmlXPtrLocationSetAdd(newlocset,range);
10850 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010851 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010852
Daniel Veillardf06307e2001-07-03 10:35:50 +000010853 /*
10854 * Cleanup
10855 */
10856 if (res != NULL)
10857 xmlXPathFreeObject(res);
10858 if (ctxt->value == tmp) {
10859 res = valuePop(ctxt);
10860 xmlXPathFreeObject(res);
10861 }
10862
10863 ctxt->context->node = NULL;
10864 }
William M. Brack72ee48d2003-12-30 08:30:19 +000010865 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000010866 CHECK_TYPE0(XPATH_NODESET);
10867 obj = valuePop(ctxt);
10868 oldset = obj->nodesetval;
10869 ctxt->context->node = NULL;
10870
10871 newlocset = xmlXPtrLocationSetCreate(NULL);
10872
10873 if (oldset != NULL) {
10874 for (i = 0; i < oldset->nodeNr; i++) {
10875 /*
10876 * Run the evaluation with a node list made of a single item
10877 * in the nodeset.
10878 */
10879 ctxt->context->node = oldset->nodeTab[i];
10880 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10881 valuePush(ctxt, tmp);
10882
10883 if (op->ch2 != -1)
10884 total +=
10885 xmlXPathCompOpEval(ctxt,
10886 &comp->steps[op->ch2]);
10887 CHECK_ERROR0;
10888
William M. Brack08171912003-12-29 02:52:11 +000010889 res = valuePop(ctxt);
10890 range =
10891 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10892 res);
10893 if (range != NULL) {
10894 xmlXPtrLocationSetAdd(newlocset, range);
10895 }
10896
10897 /*
10898 * Cleanup
10899 */
10900 if (res != NULL)
10901 xmlXPathFreeObject(res);
10902 if (ctxt->value == tmp) {
10903 res = valuePop(ctxt);
10904 xmlXPathFreeObject(res);
10905 }
10906
10907 ctxt->context->node = NULL;
10908 }
10909 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010910 }
10911
10912 /*
10913 * The result is used as the new evaluation set.
10914 */
10915 xmlXPathFreeObject(obj);
10916 ctxt->context->node = NULL;
10917 ctxt->context->contextSize = -1;
10918 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010919 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010920 return (total);
10921 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010922#endif /* LIBXML_XPTR_ENABLED */
10923 }
10924 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010925 "XPath: unknown precompiled operation %d\n", op->op);
10926 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010927}
10928
Daniel Veillard56de87e2005-02-16 00:22:29 +000010929#ifdef XPATH_STREAMING
10930/**
10931 * xmlXPathRunStreamEval:
10932 * @ctxt: the XPath parser context with the compiled expression
10933 *
10934 * Evaluate the Precompiled Streamable XPath expression in the given context.
10935 */
10936static xmlXPathObjectPtr
10937xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp) {
10938 int max_depth;
10939 int from_root;
10940 int ret, depth;
William M. Brack12d37ab2005-02-21 13:54:07 +000010941 xmlNodePtr cur = NULL, limit = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000010942 xmlXPathObjectPtr retval;
10943 xmlStreamCtxtPtr patstream;
10944
10945 int nb_nodes = 0;
10946
10947 if ((ctxt == NULL) || (comp == NULL))
10948 return(NULL);
10949 max_depth = xmlPatternMaxDepth(comp);
10950 if (max_depth == -1)
10951 return(NULL);
10952 if (max_depth == -2)
10953 max_depth = 10000;
10954 from_root = xmlPatternFromRoot(comp);
10955 if (from_root < 0)
10956 return(NULL);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000010957#if 0
10958 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
10959#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000010960
10961 retval = xmlXPathNewNodeSet(NULL);
10962 if (retval == NULL)
10963 return(NULL);
10964
Daniel Veillard56de87e2005-02-16 00:22:29 +000010965 if ((from_root) && (max_depth == 0)) {
10966 xmlXPathNodeSetAddUnique(retval->nodesetval, (xmlNodePtr) ctxt->doc);
10967 return(retval);
10968 } else if (max_depth == 0) {
10969 xmlXPathNodeSetAddUnique(retval->nodesetval, ctxt->node);
10970 return(retval);
10971 }
10972 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000010973 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000010974 } else if (ctxt->node != NULL) {
10975 switch (ctxt->node->type) {
10976 case XML_ELEMENT_NODE:
10977 case XML_DOCUMENT_NODE:
10978 case XML_DOCUMENT_FRAG_NODE:
10979 case XML_HTML_DOCUMENT_NODE:
10980#ifdef LIBXML_DOCB_ENABLED
10981 case XML_DOCB_DOCUMENT_NODE:
10982#endif
10983 cur = ctxt->node;
10984 break;
10985 case XML_ATTRIBUTE_NODE:
10986 case XML_TEXT_NODE:
10987 case XML_CDATA_SECTION_NODE:
10988 case XML_ENTITY_REF_NODE:
10989 case XML_ENTITY_NODE:
10990 case XML_PI_NODE:
10991 case XML_COMMENT_NODE:
10992 case XML_NOTATION_NODE:
10993 case XML_DTD_NODE:
10994 case XML_DOCUMENT_TYPE_NODE:
10995 case XML_ELEMENT_DECL:
10996 case XML_ATTRIBUTE_DECL:
10997 case XML_ENTITY_DECL:
10998 case XML_NAMESPACE_DECL:
10999 case XML_XINCLUDE_START:
11000 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000011001 break;
11002 }
11003 limit = cur;
11004 }
11005 if (cur == NULL)
11006 return(retval);
11007
11008 patstream = xmlPatternGetStreamCtxt(comp);
11009 if (patstream == NULL) {
11010 return(retval);
11011 }
11012
11013 if (from_root) {
11014 ret = xmlStreamPush(patstream, NULL, NULL);
11015 if (ret < 0) {
11016 } else if (ret == 1) {
11017 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11018 }
11019 }
11020
11021 depth = 0;
11022 goto scan_children;
11023 do {
11024next_node:
11025 nb_nodes++;
11026 if (cur->type == XML_ELEMENT_NODE) {
11027 ret = xmlStreamPush(patstream, cur->name,
11028 (cur->ns ? cur->ns->href : NULL));
11029 if (ret < 0) {
11030 } else if (ret == 1) {
11031 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11032 }
11033 if ((cur->children == NULL) || (depth >= max_depth)) {
11034 ret = xmlStreamPop(patstream);
11035 }
11036 }
11037
11038scan_children:
11039 if ((cur->children != NULL) && (depth < max_depth)) {
11040 /*
11041 * Do not descend on entities declarations
11042 */
11043 if (cur->children->type != XML_ENTITY_DECL) {
11044 cur = cur->children;
11045 depth++;
11046 /*
11047 * Skip DTDs
11048 */
11049 if (cur->type != XML_DTD_NODE)
11050 continue;
11051 }
11052 }
11053
11054 if (cur == limit)
11055 break;
11056
11057 while (cur->next != NULL) {
11058 cur = cur->next;
11059 if ((cur->type != XML_ENTITY_DECL) &&
11060 (cur->type != XML_DTD_NODE))
11061 goto next_node;
11062 }
11063
11064 do {
11065 ret = xmlStreamPop(patstream);
11066 cur = cur->parent;
11067 depth--;
11068 if ((cur == NULL) || (cur == limit))
11069 goto done;
11070 if (cur->next != NULL) {
11071 cur = cur->next;
11072 break;
11073 }
11074 } while (cur != NULL);
11075
11076 } while ((cur != NULL) && (depth >= 0));
11077done:
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000011078#if 0
11079 printf("stream eval: checked %d nodes selected %d\n",
11080 nb_nodes, retval->nodesetval->nodeNr);
11081#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011082 xmlFreeStreamCtxt(patstream);
11083 return(retval);
11084}
11085#endif /* XPATH_STREAMING */
11086
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011087/**
11088 * xmlXPathRunEval:
11089 * @ctxt: the XPath parser context with the compiled expression
11090 *
11091 * Evaluate the Precompiled XPath expression in the given context.
11092 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011093static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011094xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
11095 xmlXPathCompExprPtr comp;
11096
11097 if ((ctxt == NULL) || (ctxt->comp == NULL))
11098 return;
11099
11100 if (ctxt->valueTab == NULL) {
11101 /* Allocate the value stack */
11102 ctxt->valueTab = (xmlXPathObjectPtr *)
11103 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
11104 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000011105 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011106 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011107 }
11108 ctxt->valueNr = 0;
11109 ctxt->valueMax = 10;
11110 ctxt->value = NULL;
11111 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011112#ifdef XPATH_STREAMING
11113 if (ctxt->comp->stream) {
11114 xmlXPathObjectPtr ret;
11115 ret = xmlXPathRunStreamEval(ctxt->context, ctxt->comp->stream);
11116 if (ret != NULL) {
11117 valuePush(ctxt, ret);
11118 return;
11119 }
11120 }
11121#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011122 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000011123 if(comp->last < 0) {
11124 xmlGenericError(xmlGenericErrorContext,
11125 "xmlXPathRunEval: last is less than zero\n");
11126 return;
11127 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011128 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11129}
11130
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011131/************************************************************************
11132 * *
11133 * Public interfaces *
11134 * *
11135 ************************************************************************/
11136
11137/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011138 * xmlXPathEvalPredicate:
11139 * @ctxt: the XPath context
11140 * @res: the Predicate Expression evaluation result
11141 *
11142 * Evaluate a predicate result for the current node.
11143 * A PredicateExpr is evaluated by evaluating the Expr and converting
11144 * the result to a boolean. If the result is a number, the result will
11145 * be converted to true if the number is equal to the position of the
11146 * context node in the context node list (as returned by the position
11147 * function) and will be converted to false otherwise; if the result
11148 * is not a number, then the result will be converted as if by a call
11149 * to the boolean function.
11150 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011151 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011152 */
11153int
11154xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000011155 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011156 switch (res->type) {
11157 case XPATH_BOOLEAN:
11158 return(res->boolval);
11159 case XPATH_NUMBER:
11160 return(res->floatval == ctxt->proximityPosition);
11161 case XPATH_NODESET:
11162 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011163 if (res->nodesetval == NULL)
11164 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011165 return(res->nodesetval->nodeNr != 0);
11166 case XPATH_STRING:
11167 return((res->stringval != NULL) &&
11168 (xmlStrlen(res->stringval) != 0));
11169 default:
11170 STRANGE
11171 }
11172 return(0);
11173}
11174
11175/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011176 * xmlXPathEvaluatePredicateResult:
11177 * @ctxt: the XPath Parser context
11178 * @res: the Predicate Expression evaluation result
11179 *
11180 * Evaluate a predicate result for the current node.
11181 * A PredicateExpr is evaluated by evaluating the Expr and converting
11182 * the result to a boolean. If the result is a number, the result will
11183 * be converted to true if the number is equal to the position of the
11184 * context node in the context node list (as returned by the position
11185 * function) and will be converted to false otherwise; if the result
11186 * is not a number, then the result will be converted as if by a call
11187 * to the boolean function.
11188 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011189 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011190 */
11191int
11192xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
11193 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000011194 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011195 switch (res->type) {
11196 case XPATH_BOOLEAN:
11197 return(res->boolval);
11198 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000011199#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000011200 return((res->floatval == ctxt->context->proximityPosition) &&
11201 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000011202#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011203 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000011204#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011205 case XPATH_NODESET:
11206 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000011207 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000011208 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011209 return(res->nodesetval->nodeNr != 0);
11210 case XPATH_STRING:
11211 return((res->stringval != NULL) &&
11212 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000011213#ifdef LIBXML_XPTR_ENABLED
11214 case XPATH_LOCATIONSET:{
11215 xmlLocationSetPtr ptr = res->user;
11216 if (ptr == NULL)
11217 return(0);
11218 return (ptr->locNr != 0);
11219 }
11220#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011221 default:
11222 STRANGE
11223 }
11224 return(0);
11225}
11226
Daniel Veillard56de87e2005-02-16 00:22:29 +000011227#ifdef XPATH_STREAMING
11228/**
11229 * xmlXPathTryStreamCompile:
11230 * @ctxt: an XPath context
11231 * @str: the XPath expression
11232 *
11233 * Try to compile the XPath expression as a streamable subset.
11234 *
11235 * Returns the compiled expression or NULL if failed to compile.
11236 */
11237static xmlXPathCompExprPtr
11238xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11239 /*
11240 * Optimization: use streaming patterns when the XPath expression can
11241 * be compiled to a stream lookup
11242 */
11243 xmlPatternPtr stream;
11244 xmlXPathCompExprPtr comp;
11245 xmlDictPtr dict = NULL;
11246 const xmlChar **namespaces = NULL;
11247 xmlNsPtr ns;
11248 int i, j;
11249
11250 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
11251 (!xmlStrchr(str, '@'))) {
11252 if (ctxt != NULL) {
11253 dict = ctxt->dict;
11254 if (ctxt->nsNr > 0) {
11255 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1));
11256 if (namespaces == NULL) {
11257 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
11258 return(NULL);
11259 }
11260 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
11261 ns = ctxt->namespaces[j];
11262 namespaces[i++] = ns->href;
11263 namespaces[i++] = ns->prefix;
11264 }
11265 namespaces[i++] = NULL;
11266 namespaces[i++] = NULL;
11267 }
11268 }
11269
11270 stream = xmlPatterncompile(str, dict, 0, &namespaces[0]);
11271 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
11272 comp = xmlXPathNewCompExpr();
11273 if (comp == NULL) {
11274 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
11275 return(NULL);
11276 }
11277 comp->stream = stream;
11278 comp->dict = dict;
11279 if (comp->dict)
11280 xmlDictReference(comp->dict);
11281 return(comp);
11282 }
11283 xmlFreePattern(stream);
11284 }
11285 return(NULL);
11286}
11287#endif /* XPATH_STREAMING */
11288
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011289/**
Daniel Veillard4773df22004-01-23 13:15:13 +000011290 * xmlXPathCtxtCompile:
11291 * @ctxt: an XPath context
11292 * @str: the XPath expression
11293 *
11294 * Compile an XPath expression
11295 *
11296 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
11297 * the caller has to free the object.
11298 */
11299xmlXPathCompExprPtr
11300xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11301 xmlXPathParserContextPtr pctxt;
11302 xmlXPathCompExprPtr comp;
11303
Daniel Veillard56de87e2005-02-16 00:22:29 +000011304#ifdef XPATH_STREAMING
11305 comp = xmlXPathTryStreamCompile(ctxt, str);
11306 if (comp != NULL)
11307 return(comp);
11308#endif
11309
Daniel Veillard4773df22004-01-23 13:15:13 +000011310 xmlXPathInit();
11311
11312 pctxt = xmlXPathNewParserContext(str, ctxt);
11313 xmlXPathCompileExpr(pctxt);
11314
11315 if( pctxt->error != XPATH_EXPRESSION_OK )
11316 {
11317 xmlXPathFreeParserContext(pctxt);
11318 return (0);
11319 }
11320
11321 if (*pctxt->cur != 0) {
11322 /*
11323 * aleksey: in some cases this line prints *second* error message
11324 * (see bug #78858) and probably this should be fixed.
11325 * However, we are not sure that all error messages are printed
11326 * out in other places. It's not critical so we leave it as-is for now
11327 */
11328 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11329 comp = NULL;
11330 } else {
11331 comp = pctxt->comp;
11332 pctxt->comp = NULL;
11333 }
11334 xmlXPathFreeParserContext(pctxt);
11335 if (comp != NULL) {
11336 comp->expr = xmlStrdup(str);
11337#ifdef DEBUG_EVAL_COUNTS
11338 comp->string = xmlStrdup(str);
11339 comp->nb = 0;
11340#endif
11341 }
11342 return(comp);
11343}
11344
11345/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011346 * xmlXPathCompile:
11347 * @str: the XPath expression
11348 *
11349 * Compile an XPath expression
11350 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000011351 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011352 * the caller has to free the object.
11353 */
11354xmlXPathCompExprPtr
11355xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000011356 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011357}
11358
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011359/**
11360 * xmlXPathCompiledEval:
11361 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000011362 * @ctx: the XPath context
11363 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011364 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000011365 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011366 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000011367 * the caller has to free the object.
11368 */
11369xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011370xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000011371 xmlXPathParserContextPtr ctxt;
11372 xmlXPathObjectPtr res, tmp, init = NULL;
11373 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000011374#ifndef LIBXML_THREAD_ENABLED
11375 static int reentance = 0;
11376#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011377
William M. Brackf13f77f2004-11-12 16:03:48 +000011378 CHECK_CTXT(ctx)
11379
11380 if (comp == NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011381 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011382 xmlXPathInit();
11383
Daniel Veillard81463942001-10-16 12:34:39 +000011384#ifndef LIBXML_THREAD_ENABLED
11385 reentance++;
11386 if (reentance > 1)
11387 xmlXPathDisableOptimizer = 1;
11388#endif
11389
Daniel Veillardf06307e2001-07-03 10:35:50 +000011390#ifdef DEBUG_EVAL_COUNTS
11391 comp->nb++;
11392 if ((comp->string != NULL) && (comp->nb > 100)) {
11393 fprintf(stderr, "100 x %s\n", comp->string);
11394 comp->nb = 0;
11395 }
11396#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011397 ctxt = xmlXPathCompParserContext(comp, ctx);
11398 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011399
11400 if (ctxt->value == NULL) {
11401 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011402 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011403 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011404 } else {
11405 res = valuePop(ctxt);
11406 }
11407
Daniel Veillardf06307e2001-07-03 10:35:50 +000011408
Owen Taylor3473f882001-02-23 17:55:21 +000011409 do {
11410 tmp = valuePop(ctxt);
11411 if (tmp != NULL) {
11412 if (tmp != init)
11413 stack++;
11414 xmlXPathFreeObject(tmp);
11415 }
11416 } while (tmp != NULL);
11417 if ((stack != 0) && (res != NULL)) {
11418 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011419 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011420 stack);
11421 }
11422 if (ctxt->error != XPATH_EXPRESSION_OK) {
11423 xmlXPathFreeObject(res);
11424 res = NULL;
11425 }
11426
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011427
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011428 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011429 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011430#ifndef LIBXML_THREAD_ENABLED
11431 reentance--;
11432#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011433 return(res);
11434}
11435
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011436/**
11437 * xmlXPathEvalExpr:
11438 * @ctxt: the XPath Parser context
11439 *
11440 * Parse and evaluate an XPath expression in the given context,
11441 * then push the result on the context stack
11442 */
11443void
11444xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011445#ifdef XPATH_STREAMING
11446 xmlXPathCompExprPtr comp;
11447#endif
11448
Daniel Veillarda82b1822004-11-08 16:24:57 +000011449 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011450
11451#ifdef XPATH_STREAMING
11452 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
11453 if (comp != NULL) {
11454 if (ctxt->comp != NULL)
11455 xmlXPathFreeCompExpr(ctxt->comp);
11456 ctxt->comp = comp;
11457 if (ctxt->cur != NULL)
11458 while (*ctxt->cur != 0) ctxt->cur++;
11459 } else
11460#endif
11461 {
11462 xmlXPathCompileExpr(ctxt);
11463 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011464 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011465 xmlXPathRunEval(ctxt);
11466}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011467
11468/**
11469 * xmlXPathEval:
11470 * @str: the XPath expression
11471 * @ctx: the XPath context
11472 *
11473 * Evaluate the XPath Location Path in the given context.
11474 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011475 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011476 * the caller has to free the object.
11477 */
11478xmlXPathObjectPtr
11479xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11480 xmlXPathParserContextPtr ctxt;
11481 xmlXPathObjectPtr res, tmp, init = NULL;
11482 int stack = 0;
11483
William M. Brackf13f77f2004-11-12 16:03:48 +000011484 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011485
William M. Brackf13f77f2004-11-12 16:03:48 +000011486 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011487
11488 ctxt = xmlXPathNewParserContext(str, ctx);
11489 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011490
11491 if (ctxt->value == NULL) {
11492 xmlGenericError(xmlGenericErrorContext,
11493 "xmlXPathEval: evaluation failed\n");
11494 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011495 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
11496#ifdef XPATH_STREAMING
11497 && (ctxt->comp->stream == NULL)
11498#endif
11499 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011500 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11501 res = NULL;
11502 } else {
11503 res = valuePop(ctxt);
11504 }
11505
11506 do {
11507 tmp = valuePop(ctxt);
11508 if (tmp != NULL) {
11509 if (tmp != init)
11510 stack++;
11511 xmlXPathFreeObject(tmp);
11512 }
11513 } while (tmp != NULL);
11514 if ((stack != 0) && (res != NULL)) {
11515 xmlGenericError(xmlGenericErrorContext,
11516 "xmlXPathEval: %d object left on the stack\n",
11517 stack);
11518 }
11519 if (ctxt->error != XPATH_EXPRESSION_OK) {
11520 xmlXPathFreeObject(res);
11521 res = NULL;
11522 }
11523
Owen Taylor3473f882001-02-23 17:55:21 +000011524 xmlXPathFreeParserContext(ctxt);
11525 return(res);
11526}
11527
11528/**
11529 * xmlXPathEvalExpression:
11530 * @str: the XPath expression
11531 * @ctxt: the XPath context
11532 *
11533 * Evaluate the XPath expression in the given context.
11534 *
11535 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11536 * the caller has to free the object.
11537 */
11538xmlXPathObjectPtr
11539xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11540 xmlXPathParserContextPtr pctxt;
11541 xmlXPathObjectPtr res, tmp;
11542 int stack = 0;
11543
William M. Brackf13f77f2004-11-12 16:03:48 +000011544 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000011545
William M. Brackf13f77f2004-11-12 16:03:48 +000011546 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000011547
11548 pctxt = xmlXPathNewParserContext(str, ctxt);
11549 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011550
11551 if (*pctxt->cur != 0) {
11552 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11553 res = NULL;
11554 } else {
11555 res = valuePop(pctxt);
11556 }
11557 do {
11558 tmp = valuePop(pctxt);
11559 if (tmp != NULL) {
11560 xmlXPathFreeObject(tmp);
11561 stack++;
11562 }
11563 } while (tmp != NULL);
11564 if ((stack != 0) && (res != NULL)) {
11565 xmlGenericError(xmlGenericErrorContext,
11566 "xmlXPathEvalExpression: %d object left on the stack\n",
11567 stack);
11568 }
11569 xmlXPathFreeParserContext(pctxt);
11570 return(res);
11571}
11572
Daniel Veillard42766c02002-08-22 20:52:17 +000011573/************************************************************************
11574 * *
11575 * Extra functions not pertaining to the XPath spec *
11576 * *
11577 ************************************************************************/
11578/**
11579 * xmlXPathEscapeUriFunction:
11580 * @ctxt: the XPath Parser context
11581 * @nargs: the number of arguments
11582 *
11583 * Implement the escape-uri() XPath function
11584 * string escape-uri(string $str, bool $escape-reserved)
11585 *
11586 * This function applies the URI escaping rules defined in section 2 of [RFC
11587 * 2396] to the string supplied as $uri-part, which typically represents all
11588 * or part of a URI. The effect of the function is to replace any special
11589 * character in the string by an escape sequence of the form %xx%yy...,
11590 * where xxyy... is the hexadecimal representation of the octets used to
11591 * represent the character in UTF-8.
11592 *
11593 * The set of characters that are escaped depends on the setting of the
11594 * boolean argument $escape-reserved.
11595 *
11596 * If $escape-reserved is true, all characters are escaped other than lower
11597 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11598 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11599 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11600 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11601 * A-F).
11602 *
11603 * If $escape-reserved is false, the behavior differs in that characters
11604 * referred to in [RFC 2396] as reserved characters are not escaped. These
11605 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11606 *
11607 * [RFC 2396] does not define whether escaped URIs should use lower case or
11608 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11609 * compared using string comparison functions, this function must always use
11610 * the upper-case letters A-F.
11611 *
11612 * Generally, $escape-reserved should be set to true when escaping a string
11613 * that is to form a single part of a URI, and to false when escaping an
11614 * entire URI or URI reference.
11615 *
11616 * In the case of non-ascii characters, the string is encoded according to
11617 * utf-8 and then converted according to RFC 2396.
11618 *
11619 * Examples
11620 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11621 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11622 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11623 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11624 *
11625 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011626static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011627xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11628 xmlXPathObjectPtr str;
11629 int escape_reserved;
11630 xmlBufferPtr target;
11631 xmlChar *cptr;
11632 xmlChar escape[4];
11633
11634 CHECK_ARITY(2);
11635
11636 escape_reserved = xmlXPathPopBoolean(ctxt);
11637
11638 CAST_TO_STRING;
11639 str = valuePop(ctxt);
11640
11641 target = xmlBufferCreate();
11642
11643 escape[0] = '%';
11644 escape[3] = 0;
11645
11646 if (target) {
11647 for (cptr = str->stringval; *cptr; cptr++) {
11648 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11649 (*cptr >= 'a' && *cptr <= 'z') ||
11650 (*cptr >= '0' && *cptr <= '9') ||
11651 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11652 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11653 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11654 (*cptr == '%' &&
11655 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11656 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11657 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11658 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11659 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11660 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11661 (!escape_reserved &&
11662 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11663 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11664 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11665 *cptr == ','))) {
11666 xmlBufferAdd(target, cptr, 1);
11667 } else {
11668 if ((*cptr >> 4) < 10)
11669 escape[1] = '0' + (*cptr >> 4);
11670 else
11671 escape[1] = 'A' - 10 + (*cptr >> 4);
11672 if ((*cptr & 0xF) < 10)
11673 escape[2] = '0' + (*cptr & 0xF);
11674 else
11675 escape[2] = 'A' - 10 + (*cptr & 0xF);
11676
11677 xmlBufferAdd(target, &escape[0], 3);
11678 }
11679 }
11680 }
11681 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11682 xmlBufferFree(target);
11683 xmlXPathFreeObject(str);
11684}
11685
Owen Taylor3473f882001-02-23 17:55:21 +000011686/**
11687 * xmlXPathRegisterAllFunctions:
11688 * @ctxt: the XPath context
11689 *
11690 * Registers all default XPath functions in this context
11691 */
11692void
11693xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11694{
11695 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11696 xmlXPathBooleanFunction);
11697 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11698 xmlXPathCeilingFunction);
11699 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11700 xmlXPathCountFunction);
11701 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11702 xmlXPathConcatFunction);
11703 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11704 xmlXPathContainsFunction);
11705 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11706 xmlXPathIdFunction);
11707 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11708 xmlXPathFalseFunction);
11709 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11710 xmlXPathFloorFunction);
11711 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11712 xmlXPathLastFunction);
11713 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11714 xmlXPathLangFunction);
11715 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11716 xmlXPathLocalNameFunction);
11717 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11718 xmlXPathNotFunction);
11719 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11720 xmlXPathNameFunction);
11721 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11722 xmlXPathNamespaceURIFunction);
11723 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11724 xmlXPathNormalizeFunction);
11725 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11726 xmlXPathNumberFunction);
11727 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11728 xmlXPathPositionFunction);
11729 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11730 xmlXPathRoundFunction);
11731 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11732 xmlXPathStringFunction);
11733 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11734 xmlXPathStringLengthFunction);
11735 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11736 xmlXPathStartsWithFunction);
11737 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11738 xmlXPathSubstringFunction);
11739 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11740 xmlXPathSubstringBeforeFunction);
11741 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11742 xmlXPathSubstringAfterFunction);
11743 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11744 xmlXPathSumFunction);
11745 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11746 xmlXPathTrueFunction);
11747 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11748 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011749
11750 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11751 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11752 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011753}
11754
11755#endif /* LIBXML_XPATH_ENABLED */