blob: 4e7941e704e723f5bde8d74f016f6e3a1974c1b3 [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
59/* currently only in testing for DV as it's not yet solid enough for XSLT */
60/*
61 * TODO:
62 * - fix the | where there is both relative and absolute expressions
63 * probably need new pattens APIs to separate both e.g "//b | a "
64 * - fix also the 0 depth trick used for "/" and "." when or'ed
65 * - double check /. is a noop
66 * - libxslt tests show a mem leak of a few bytes
67 */
68/* #define XPATH_STREAMING */
69#endif
Owen Taylor3473f882001-02-23 17:55:21 +000070
Daniel Veillardd96f6d32003-10-07 21:25:12 +000071#define TODO \
72 xmlGenericError(xmlGenericErrorContext, \
73 "Unimplemented block at %s:%d\n", \
74 __FILE__, __LINE__);
75
William M. Brackd1757ab2004-10-02 22:07:48 +000076/*
77 * TODO:
78 * There are a few spots where some tests are done which depend upon ascii
79 * data. These should be enhanced for full UTF8 support (see particularly
80 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
81 */
82
William M. Brack21e4ef22005-01-02 09:53:13 +000083#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000084/************************************************************************
85 * *
86 * Floating point stuff *
87 * *
88 ************************************************************************/
89
Daniel Veillardc0631a62001-09-20 13:56:06 +000090#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000091#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000092#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000093#include "trionan.c"
94
Owen Taylor3473f882001-02-23 17:55:21 +000095/*
Owen Taylor3473f882001-02-23 17:55:21 +000096 * The lack of portability of this section of the libc is annoying !
97 */
98double xmlXPathNAN = 0;
99double xmlXPathPINF = 1;
100double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000101double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000102static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000103
Owen Taylor3473f882001-02-23 17:55:21 +0000104/**
105 * xmlXPathInit:
106 *
107 * Initialize the XPath environment
108 */
109void
110xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000111 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000112
Bjorn Reese45029602001-08-21 09:23:53 +0000113 xmlXPathPINF = trio_pinf();
114 xmlXPathNINF = trio_ninf();
115 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000116 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000117
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000118 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000119}
120
Daniel Veillardcda96922001-08-21 10:56:31 +0000121/**
122 * xmlXPathIsNaN:
123 * @val: a double value
124 *
125 * Provides a portable isnan() function to detect whether a double
126 * is a NotaNumber. Based on trio code
127 * http://sourceforge.net/projects/ctrio/
128 *
129 * Returns 1 if the value is a NaN, 0 otherwise
130 */
131int
132xmlXPathIsNaN(double val) {
133 return(trio_isnan(val));
134}
135
136/**
137 * xmlXPathIsInf:
138 * @val: a double value
139 *
140 * Provides a portable isinf() function to detect whether a double
141 * is a +Infinite or -Infinite. Based on trio code
142 * http://sourceforge.net/projects/ctrio/
143 *
144 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
145 */
146int
147xmlXPathIsInf(double val) {
148 return(trio_isinf(val));
149}
150
Daniel Veillard4432df22003-09-28 18:58:27 +0000151#endif /* SCHEMAS or XPATH */
152#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000153/**
154 * xmlXPathGetSign:
155 * @val: a double value
156 *
157 * Provides a portable function to detect the sign of a double
158 * Modified from trio code
159 * http://sourceforge.net/projects/ctrio/
160 *
161 * Returns 1 if the value is Negative, 0 if positive
162 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000163static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000164xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000165 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000166}
167
168
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000169/*
170 * TODO: when compatibility allows remove all "fake node libxslt" strings
171 * the test should just be name[0] = ' '
172 */
173/* #define DEBUG */
174/* #define DEBUG_STEP */
175/* #define DEBUG_STEP_NTH */
176/* #define DEBUG_EXPR */
177/* #define DEBUG_EVAL_COUNTS */
178
179static xmlNs xmlXPathXMLNamespaceStruct = {
180 NULL,
181 XML_NAMESPACE_DECL,
182 XML_XML_NAMESPACE,
183 BAD_CAST "xml",
184 NULL
185};
186static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
187#ifndef LIBXML_THREAD_ENABLED
188/*
189 * Optimizer is disabled only when threaded apps are detected while
190 * the library ain't compiled for thread safety.
191 */
192static int xmlXPathDisableOptimizer = 0;
193#endif
194
Owen Taylor3473f882001-02-23 17:55:21 +0000195/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000196 * *
197 * Error handling routines *
198 * *
199 ************************************************************************/
200
William M. Brack08171912003-12-29 02:52:11 +0000201/*
202 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
203 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000204static const char *xmlXPathErrorMessages[] = {
205 "Ok\n",
206 "Number encoding\n",
207 "Unfinished literal\n",
208 "Start of literal\n",
209 "Expected $ for variable reference\n",
210 "Undefined variable\n",
211 "Invalid predicate\n",
212 "Invalid expression\n",
213 "Missing closing curly brace\n",
214 "Unregistered function\n",
215 "Invalid operand\n",
216 "Invalid type\n",
217 "Invalid number of arguments\n",
218 "Invalid context size\n",
219 "Invalid context position\n",
220 "Memory allocation error\n",
221 "Syntax error\n",
222 "Resource error\n",
223 "Sub resource error\n",
224 "Undefined namespace prefix\n",
225 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000226 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000227 "Invalid or incomplete context\n",
228 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000229};
William M. Brackcd65bc92005-01-06 09:39:18 +0000230#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
231 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000232/**
233 * xmlXPathErrMemory:
234 * @ctxt: an XPath context
235 * @extra: extra informations
236 *
237 * Handle a redefinition of attribute error
238 */
239static void
240xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
241{
242 if (ctxt != NULL) {
243 if (extra) {
244 xmlChar buf[200];
245
246 xmlStrPrintf(buf, 200,
247 BAD_CAST "Memory allocation failed : %s\n",
248 extra);
249 ctxt->lastError.message = (char *) xmlStrdup(buf);
250 } else {
251 ctxt->lastError.message = (char *)
252 xmlStrdup(BAD_CAST "Memory allocation failed\n");
253 }
254 ctxt->lastError.domain = XML_FROM_XPATH;
255 ctxt->lastError.code = XML_ERR_NO_MEMORY;
256 if (ctxt->error != NULL)
257 ctxt->error(ctxt->userData, &ctxt->lastError);
258 } else {
259 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000260 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000261 NULL, NULL, XML_FROM_XPATH,
262 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
263 extra, NULL, NULL, 0, 0,
264 "Memory allocation failed : %s\n", extra);
265 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000266 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000267 NULL, NULL, XML_FROM_XPATH,
268 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
269 NULL, NULL, NULL, 0, 0,
270 "Memory allocation failed\n");
271 }
272}
273
274/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000275 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000276 * @ctxt: an XPath parser context
277 * @extra: extra informations
278 *
279 * Handle a redefinition of attribute error
280 */
281static void
282xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
283{
284 ctxt->error = XPATH_MEMORY_ERROR;
285 if (ctxt == NULL)
286 xmlXPathErrMemory(NULL, extra);
287 else
288 xmlXPathErrMemory(ctxt->context, extra);
289}
290
291/**
292 * xmlXPathErr:
293 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000294 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000295 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000296 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000297 */
298void
299xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
300{
William M. Brackcd65bc92005-01-06 09:39:18 +0000301 if ((error < 0) || (error > MAXERRNO))
302 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000303 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000304 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000305 NULL, NULL, XML_FROM_XPATH,
306 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
307 XML_ERR_ERROR, NULL, 0,
308 NULL, NULL, NULL, 0, 0,
309 xmlXPathErrorMessages[error]);
310 return;
311 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000312 ctxt->error = error;
313 if (ctxt->context == NULL) {
314 __xmlRaiseError(NULL, NULL, NULL,
315 NULL, NULL, XML_FROM_XPATH,
316 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
317 XML_ERR_ERROR, NULL, 0,
318 (const char *) ctxt->base, NULL, NULL,
319 ctxt->cur - ctxt->base, 0,
320 xmlXPathErrorMessages[error]);
321 return;
322 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000323 ctxt->context->lastError.domain = XML_FROM_XPATH;
324 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
325 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000326 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000327 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
328 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
329 ctxt->context->lastError.node = ctxt->context->debugNode;
330 if (ctxt->context->error != NULL) {
331 ctxt->context->error(ctxt->context->userData,
332 &ctxt->context->lastError);
333 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000334 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000335 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
336 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
337 XML_ERR_ERROR, NULL, 0,
338 (const char *) ctxt->base, NULL, NULL,
339 ctxt->cur - ctxt->base, 0,
340 xmlXPathErrorMessages[error]);
341 }
342
343}
344
345/**
346 * xmlXPatherror:
347 * @ctxt: the XPath Parser context
348 * @file: the file name
349 * @line: the line number
350 * @no: the error number
351 *
352 * Formats an error message.
353 */
354void
355xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
356 int line ATTRIBUTE_UNUSED, int no) {
357 xmlXPathErr(ctxt, no);
358}
359
360
361/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000362 * *
363 * Parser Types *
364 * *
365 ************************************************************************/
366
367/*
368 * Types are private:
369 */
370
371typedef enum {
372 XPATH_OP_END=0,
373 XPATH_OP_AND,
374 XPATH_OP_OR,
375 XPATH_OP_EQUAL,
376 XPATH_OP_CMP,
377 XPATH_OP_PLUS,
378 XPATH_OP_MULT,
379 XPATH_OP_UNION,
380 XPATH_OP_ROOT,
381 XPATH_OP_NODE,
382 XPATH_OP_RESET,
383 XPATH_OP_COLLECT,
384 XPATH_OP_VALUE,
385 XPATH_OP_VARIABLE,
386 XPATH_OP_FUNCTION,
387 XPATH_OP_ARG,
388 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000389 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000390 XPATH_OP_SORT
391#ifdef LIBXML_XPTR_ENABLED
392 ,XPATH_OP_RANGETO
393#endif
394} xmlXPathOp;
395
396typedef enum {
397 AXIS_ANCESTOR = 1,
398 AXIS_ANCESTOR_OR_SELF,
399 AXIS_ATTRIBUTE,
400 AXIS_CHILD,
401 AXIS_DESCENDANT,
402 AXIS_DESCENDANT_OR_SELF,
403 AXIS_FOLLOWING,
404 AXIS_FOLLOWING_SIBLING,
405 AXIS_NAMESPACE,
406 AXIS_PARENT,
407 AXIS_PRECEDING,
408 AXIS_PRECEDING_SIBLING,
409 AXIS_SELF
410} xmlXPathAxisVal;
411
412typedef enum {
413 NODE_TEST_NONE = 0,
414 NODE_TEST_TYPE = 1,
415 NODE_TEST_PI = 2,
416 NODE_TEST_ALL = 3,
417 NODE_TEST_NS = 4,
418 NODE_TEST_NAME = 5
419} xmlXPathTestVal;
420
421typedef enum {
422 NODE_TYPE_NODE = 0,
423 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
424 NODE_TYPE_TEXT = XML_TEXT_NODE,
425 NODE_TYPE_PI = XML_PI_NODE
426} xmlXPathTypeVal;
427
428
429typedef struct _xmlXPathStepOp xmlXPathStepOp;
430typedef xmlXPathStepOp *xmlXPathStepOpPtr;
431struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000432 xmlXPathOp op; /* The identifier of the operation */
433 int ch1; /* First child */
434 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000435 int value;
436 int value2;
437 int value3;
438 void *value4;
439 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000440 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000441 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000442};
443
444struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000445 int nbStep; /* Number of steps in this expression */
446 int maxStep; /* Maximum number of steps allocated */
447 xmlXPathStepOp *steps; /* ops for computation of this expression */
448 int last; /* index of last step in expression */
449 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000450 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000451#ifdef DEBUG_EVAL_COUNTS
452 int nb;
453 xmlChar *string;
454#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000455#ifdef XPATH_STREAMING
456 xmlPatternPtr stream;
457#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000458};
459
460/************************************************************************
461 * *
462 * Parser Type functions *
463 * *
464 ************************************************************************/
465
466/**
467 * xmlXPathNewCompExpr:
468 *
469 * Create a new Xpath component
470 *
471 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
472 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000473static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000474xmlXPathNewCompExpr(void) {
475 xmlXPathCompExprPtr cur;
476
477 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
478 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000479 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000480 return(NULL);
481 }
482 memset(cur, 0, sizeof(xmlXPathCompExpr));
483 cur->maxStep = 10;
484 cur->nbStep = 0;
485 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
486 sizeof(xmlXPathStepOp));
487 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000488 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000489 xmlFree(cur);
490 return(NULL);
491 }
492 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
493 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000494#ifdef DEBUG_EVAL_COUNTS
495 cur->nb = 0;
496#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000497 return(cur);
498}
499
500/**
501 * xmlXPathFreeCompExpr:
502 * @comp: an XPATH comp
503 *
504 * Free up the memory allocated by @comp
505 */
506void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000507xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
508{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000509 xmlXPathStepOpPtr op;
510 int i;
511
512 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000513 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000514 if (comp->dict == NULL) {
515 for (i = 0; i < comp->nbStep; i++) {
516 op = &comp->steps[i];
517 if (op->value4 != NULL) {
518 if (op->op == XPATH_OP_VALUE)
519 xmlXPathFreeObject(op->value4);
520 else
521 xmlFree(op->value4);
522 }
523 if (op->value5 != NULL)
524 xmlFree(op->value5);
525 }
526 } else {
527 for (i = 0; i < comp->nbStep; i++) {
528 op = &comp->steps[i];
529 if (op->value4 != NULL) {
530 if (op->op == XPATH_OP_VALUE)
531 xmlXPathFreeObject(op->value4);
532 }
533 }
534 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000535 }
536 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000537 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000538 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000539#ifdef DEBUG_EVAL_COUNTS
540 if (comp->string != NULL) {
541 xmlFree(comp->string);
542 }
543#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000544#ifdef XPATH_STREAMING
545 if (comp->stream != NULL) {
546 xmlFreePatternList(comp->stream);
547 }
548#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000549 if (comp->expr != NULL) {
550 xmlFree(comp->expr);
551 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000552
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000553 xmlFree(comp);
554}
555
556/**
557 * xmlXPathCompExprAdd:
558 * @comp: the compiled expression
559 * @ch1: first child index
560 * @ch2: second child index
561 * @op: an op
562 * @value: the first int value
563 * @value2: the second int value
564 * @value3: the third int value
565 * @value4: the first string value
566 * @value5: the second string value
567 *
William M. Brack08171912003-12-29 02:52:11 +0000568 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000569 *
570 * Returns -1 in case of failure, the index otherwise
571 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000572static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000573xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
574 xmlXPathOp op, int value,
575 int value2, int value3, void *value4, void *value5) {
576 if (comp->nbStep >= comp->maxStep) {
577 xmlXPathStepOp *real;
578
579 comp->maxStep *= 2;
580 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
581 comp->maxStep * sizeof(xmlXPathStepOp));
582 if (real == NULL) {
583 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000584 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000585 return(-1);
586 }
587 comp->steps = real;
588 }
589 comp->last = comp->nbStep;
590 comp->steps[comp->nbStep].ch1 = ch1;
591 comp->steps[comp->nbStep].ch2 = ch2;
592 comp->steps[comp->nbStep].op = op;
593 comp->steps[comp->nbStep].value = value;
594 comp->steps[comp->nbStep].value2 = value2;
595 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000596 if ((comp->dict != NULL) &&
597 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
598 (op == XPATH_OP_COLLECT))) {
599 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000600 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000601 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000602 xmlFree(value4);
603 } else
604 comp->steps[comp->nbStep].value4 = NULL;
605 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000606 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000607 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000608 xmlFree(value5);
609 } else
610 comp->steps[comp->nbStep].value5 = NULL;
611 } else {
612 comp->steps[comp->nbStep].value4 = value4;
613 comp->steps[comp->nbStep].value5 = value5;
614 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000615 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000616 return(comp->nbStep++);
617}
618
Daniel Veillardf06307e2001-07-03 10:35:50 +0000619/**
620 * xmlXPathCompSwap:
621 * @comp: the compiled expression
622 * @op: operation index
623 *
624 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000625 */
626static void
627xmlXPathCompSwap(xmlXPathStepOpPtr op) {
628 int tmp;
629
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000630#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000631 /*
632 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000633 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000634 * application
635 */
636 if (xmlXPathDisableOptimizer)
637 return;
638#endif
639
Daniel Veillardf06307e2001-07-03 10:35:50 +0000640 tmp = op->ch1;
641 op->ch1 = op->ch2;
642 op->ch2 = tmp;
643}
644
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000645#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
646 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
647 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000648#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
649 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
650 (op), (val), (val2), (val3), (val4), (val5))
651
652#define PUSH_LEAVE_EXPR(op, val, val2) \
653xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
654
655#define PUSH_UNARY_EXPR(op, ch, val, val2) \
656xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
657
658#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000659xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
660 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000661
662/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000663 * *
664 * Debugging related functions *
665 * *
666 ************************************************************************/
667
Owen Taylor3473f882001-02-23 17:55:21 +0000668#define STRANGE \
669 xmlGenericError(xmlGenericErrorContext, \
670 "Internal error at %s:%d\n", \
671 __FILE__, __LINE__);
672
673#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000674static void
675xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000676 int i;
677 char shift[100];
678
679 for (i = 0;((i < depth) && (i < 25));i++)
680 shift[2 * i] = shift[2 * i + 1] = ' ';
681 shift[2 * i] = shift[2 * i + 1] = 0;
682 if (cur == NULL) {
683 fprintf(output, shift);
684 fprintf(output, "Node is NULL !\n");
685 return;
686
687 }
688
689 if ((cur->type == XML_DOCUMENT_NODE) ||
690 (cur->type == XML_HTML_DOCUMENT_NODE)) {
691 fprintf(output, shift);
692 fprintf(output, " /\n");
693 } else if (cur->type == XML_ATTRIBUTE_NODE)
694 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
695 else
696 xmlDebugDumpOneNode(output, cur, depth);
697}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000698static void
699xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000700 xmlNodePtr tmp;
701 int i;
702 char shift[100];
703
704 for (i = 0;((i < depth) && (i < 25));i++)
705 shift[2 * i] = shift[2 * i + 1] = ' ';
706 shift[2 * i] = shift[2 * i + 1] = 0;
707 if (cur == NULL) {
708 fprintf(output, shift);
709 fprintf(output, "Node is NULL !\n");
710 return;
711
712 }
713
714 while (cur != NULL) {
715 tmp = cur;
716 cur = cur->next;
717 xmlDebugDumpOneNode(output, tmp, depth);
718 }
719}
Owen Taylor3473f882001-02-23 17:55:21 +0000720
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000721static void
722xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000723 int i;
724 char shift[100];
725
726 for (i = 0;((i < depth) && (i < 25));i++)
727 shift[2 * i] = shift[2 * i + 1] = ' ';
728 shift[2 * i] = shift[2 * i + 1] = 0;
729
730 if (cur == NULL) {
731 fprintf(output, shift);
732 fprintf(output, "NodeSet is NULL !\n");
733 return;
734
735 }
736
Daniel Veillard911f49a2001-04-07 15:39:35 +0000737 if (cur != NULL) {
738 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
739 for (i = 0;i < cur->nodeNr;i++) {
740 fprintf(output, shift);
741 fprintf(output, "%d", i + 1);
742 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
743 }
Owen Taylor3473f882001-02-23 17:55:21 +0000744 }
745}
746
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000747static void
748xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000749 int i;
750 char shift[100];
751
752 for (i = 0;((i < depth) && (i < 25));i++)
753 shift[2 * i] = shift[2 * i + 1] = ' ';
754 shift[2 * i] = shift[2 * i + 1] = 0;
755
756 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
757 fprintf(output, shift);
758 fprintf(output, "Value Tree is NULL !\n");
759 return;
760
761 }
762
763 fprintf(output, shift);
764 fprintf(output, "%d", i + 1);
765 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
766}
Owen Taylor3473f882001-02-23 17:55:21 +0000767#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000768static void
769xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000770 int i;
771 char shift[100];
772
773 for (i = 0;((i < depth) && (i < 25));i++)
774 shift[2 * i] = shift[2 * i + 1] = ' ';
775 shift[2 * i] = shift[2 * i + 1] = 0;
776
777 if (cur == NULL) {
778 fprintf(output, shift);
779 fprintf(output, "LocationSet is NULL !\n");
780 return;
781
782 }
783
784 for (i = 0;i < cur->locNr;i++) {
785 fprintf(output, shift);
786 fprintf(output, "%d : ", i + 1);
787 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
788 }
789}
Daniel Veillard017b1082001-06-21 11:20:21 +0000790#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000791
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000792/**
793 * xmlXPathDebugDumpObject:
794 * @output: the FILE * to dump the output
795 * @cur: the object to inspect
796 * @depth: indentation level
797 *
798 * Dump the content of the object for debugging purposes
799 */
800void
801xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000802 int i;
803 char shift[100];
804
Daniel Veillarda82b1822004-11-08 16:24:57 +0000805 if (output == NULL) return;
806
Owen Taylor3473f882001-02-23 17:55:21 +0000807 for (i = 0;((i < depth) && (i < 25));i++)
808 shift[2 * i] = shift[2 * i + 1] = ' ';
809 shift[2 * i] = shift[2 * i + 1] = 0;
810
811 fprintf(output, shift);
812
813 if (cur == NULL) {
814 fprintf(output, "Object is empty (NULL)\n");
815 return;
816 }
817 switch(cur->type) {
818 case XPATH_UNDEFINED:
819 fprintf(output, "Object is uninitialized\n");
820 break;
821 case XPATH_NODESET:
822 fprintf(output, "Object is a Node Set :\n");
823 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
824 break;
825 case XPATH_XSLT_TREE:
826 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000827 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000828 break;
829 case XPATH_BOOLEAN:
830 fprintf(output, "Object is a Boolean : ");
831 if (cur->boolval) fprintf(output, "true\n");
832 else fprintf(output, "false\n");
833 break;
834 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000835 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000836 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000837 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000838 break;
839 case -1:
840 fprintf(output, "Object is a number : -Infinity\n");
841 break;
842 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000843 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000844 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000845 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
846 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000847 } else {
848 fprintf(output, "Object is a number : %0g\n", cur->floatval);
849 }
850 }
Owen Taylor3473f882001-02-23 17:55:21 +0000851 break;
852 case XPATH_STRING:
853 fprintf(output, "Object is a string : ");
854 xmlDebugDumpString(output, cur->stringval);
855 fprintf(output, "\n");
856 break;
857 case XPATH_POINT:
858 fprintf(output, "Object is a point : index %d in node", cur->index);
859 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
860 fprintf(output, "\n");
861 break;
862 case XPATH_RANGE:
863 if ((cur->user2 == NULL) ||
864 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
865 fprintf(output, "Object is a collapsed range :\n");
866 fprintf(output, shift);
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 } else {
873 fprintf(output, "Object is a range :\n");
874 fprintf(output, shift);
875 fprintf(output, "From ");
876 if (cur->index >= 0)
877 fprintf(output, "index %d in ", cur->index);
878 fprintf(output, "node\n");
879 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
880 depth + 1);
881 fprintf(output, shift);
882 fprintf(output, "To ");
883 if (cur->index2 >= 0)
884 fprintf(output, "index %d in ", cur->index2);
885 fprintf(output, "node\n");
886 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
887 depth + 1);
888 fprintf(output, "\n");
889 }
890 break;
891 case XPATH_LOCATIONSET:
892#if defined(LIBXML_XPTR_ENABLED)
893 fprintf(output, "Object is a Location Set:\n");
894 xmlXPathDebugDumpLocationSet(output,
895 (xmlLocationSetPtr) cur->user, depth);
896#endif
897 break;
898 case XPATH_USERS:
899 fprintf(output, "Object is user defined\n");
900 break;
901 }
902}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000903
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000904static void
905xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000906 xmlXPathStepOpPtr op, int depth) {
907 int i;
908 char shift[100];
909
910 for (i = 0;((i < depth) && (i < 25));i++)
911 shift[2 * i] = shift[2 * i + 1] = ' ';
912 shift[2 * i] = shift[2 * i + 1] = 0;
913
914 fprintf(output, shift);
915 if (op == NULL) {
916 fprintf(output, "Step is NULL\n");
917 return;
918 }
919 switch (op->op) {
920 case XPATH_OP_END:
921 fprintf(output, "END"); break;
922 case XPATH_OP_AND:
923 fprintf(output, "AND"); break;
924 case XPATH_OP_OR:
925 fprintf(output, "OR"); break;
926 case XPATH_OP_EQUAL:
927 if (op->value)
928 fprintf(output, "EQUAL =");
929 else
930 fprintf(output, "EQUAL !=");
931 break;
932 case XPATH_OP_CMP:
933 if (op->value)
934 fprintf(output, "CMP <");
935 else
936 fprintf(output, "CMP >");
937 if (!op->value2)
938 fprintf(output, "=");
939 break;
940 case XPATH_OP_PLUS:
941 if (op->value == 0)
942 fprintf(output, "PLUS -");
943 else if (op->value == 1)
944 fprintf(output, "PLUS +");
945 else if (op->value == 2)
946 fprintf(output, "PLUS unary -");
947 else if (op->value == 3)
948 fprintf(output, "PLUS unary - -");
949 break;
950 case XPATH_OP_MULT:
951 if (op->value == 0)
952 fprintf(output, "MULT *");
953 else if (op->value == 1)
954 fprintf(output, "MULT div");
955 else
956 fprintf(output, "MULT mod");
957 break;
958 case XPATH_OP_UNION:
959 fprintf(output, "UNION"); break;
960 case XPATH_OP_ROOT:
961 fprintf(output, "ROOT"); break;
962 case XPATH_OP_NODE:
963 fprintf(output, "NODE"); break;
964 case XPATH_OP_RESET:
965 fprintf(output, "RESET"); break;
966 case XPATH_OP_SORT:
967 fprintf(output, "SORT"); break;
968 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000969 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
970 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
971 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000972 const xmlChar *prefix = op->value4;
973 const xmlChar *name = op->value5;
974
975 fprintf(output, "COLLECT ");
976 switch (axis) {
977 case AXIS_ANCESTOR:
978 fprintf(output, " 'ancestors' "); break;
979 case AXIS_ANCESTOR_OR_SELF:
980 fprintf(output, " 'ancestors-or-self' "); break;
981 case AXIS_ATTRIBUTE:
982 fprintf(output, " 'attributes' "); break;
983 case AXIS_CHILD:
984 fprintf(output, " 'child' "); break;
985 case AXIS_DESCENDANT:
986 fprintf(output, " 'descendant' "); break;
987 case AXIS_DESCENDANT_OR_SELF:
988 fprintf(output, " 'descendant-or-self' "); break;
989 case AXIS_FOLLOWING:
990 fprintf(output, " 'following' "); break;
991 case AXIS_FOLLOWING_SIBLING:
992 fprintf(output, " 'following-siblings' "); break;
993 case AXIS_NAMESPACE:
994 fprintf(output, " 'namespace' "); break;
995 case AXIS_PARENT:
996 fprintf(output, " 'parent' "); break;
997 case AXIS_PRECEDING:
998 fprintf(output, " 'preceding' "); break;
999 case AXIS_PRECEDING_SIBLING:
1000 fprintf(output, " 'preceding-sibling' "); break;
1001 case AXIS_SELF:
1002 fprintf(output, " 'self' "); break;
1003 }
1004 switch (test) {
1005 case NODE_TEST_NONE:
1006 fprintf(output, "'none' "); break;
1007 case NODE_TEST_TYPE:
1008 fprintf(output, "'type' "); break;
1009 case NODE_TEST_PI:
1010 fprintf(output, "'PI' "); break;
1011 case NODE_TEST_ALL:
1012 fprintf(output, "'all' "); break;
1013 case NODE_TEST_NS:
1014 fprintf(output, "'namespace' "); break;
1015 case NODE_TEST_NAME:
1016 fprintf(output, "'name' "); break;
1017 }
1018 switch (type) {
1019 case NODE_TYPE_NODE:
1020 fprintf(output, "'node' "); break;
1021 case NODE_TYPE_COMMENT:
1022 fprintf(output, "'comment' "); break;
1023 case NODE_TYPE_TEXT:
1024 fprintf(output, "'text' "); break;
1025 case NODE_TYPE_PI:
1026 fprintf(output, "'PI' "); break;
1027 }
1028 if (prefix != NULL)
1029 fprintf(output, "%s:", prefix);
1030 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001031 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001032 break;
1033
1034 }
1035 case XPATH_OP_VALUE: {
1036 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1037
1038 fprintf(output, "ELEM ");
1039 xmlXPathDebugDumpObject(output, object, 0);
1040 goto finish;
1041 }
1042 case XPATH_OP_VARIABLE: {
1043 const xmlChar *prefix = op->value5;
1044 const xmlChar *name = op->value4;
1045
1046 if (prefix != NULL)
1047 fprintf(output, "VARIABLE %s:%s", prefix, name);
1048 else
1049 fprintf(output, "VARIABLE %s", name);
1050 break;
1051 }
1052 case XPATH_OP_FUNCTION: {
1053 int nbargs = op->value;
1054 const xmlChar *prefix = op->value5;
1055 const xmlChar *name = op->value4;
1056
1057 if (prefix != NULL)
1058 fprintf(output, "FUNCTION %s:%s(%d args)",
1059 prefix, name, nbargs);
1060 else
1061 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1062 break;
1063 }
1064 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1065 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001066 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001067#ifdef LIBXML_XPTR_ENABLED
1068 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1069#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001070 default:
1071 fprintf(output, "UNKNOWN %d\n", op->op); return;
1072 }
1073 fprintf(output, "\n");
1074finish:
1075 if (op->ch1 >= 0)
1076 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1077 if (op->ch2 >= 0)
1078 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1079}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001080
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001081/**
1082 * xmlXPathDebugDumpCompExpr:
1083 * @output: the FILE * for the output
1084 * @comp: the precompiled XPath expression
1085 * @depth: the indentation level.
1086 *
1087 * Dumps the tree of the compiled XPath expression.
1088 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001089void
1090xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1091 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001092 int i;
1093 char shift[100];
1094
Daniel Veillarda82b1822004-11-08 16:24:57 +00001095 if ((output == NULL) || (comp == NULL)) return;
1096
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001097 for (i = 0;((i < depth) && (i < 25));i++)
1098 shift[2 * i] = shift[2 * i + 1] = ' ';
1099 shift[2 * i] = shift[2 * i + 1] = 0;
1100
1101 fprintf(output, shift);
1102
1103 if (comp == NULL) {
1104 fprintf(output, "Compiled Expression is NULL\n");
1105 return;
1106 }
1107 fprintf(output, "Compiled Expression : %d elements\n",
1108 comp->nbStep);
1109 i = comp->last;
1110 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1111}
Daniel Veillard017b1082001-06-21 11:20:21 +00001112#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001113
1114/************************************************************************
1115 * *
1116 * Parser stacks related functions and macros *
1117 * *
1118 ************************************************************************/
1119
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001120/**
1121 * valuePop:
1122 * @ctxt: an XPath evaluation context
1123 *
1124 * Pops the top XPath object from the value stack
1125 *
1126 * Returns the XPath object just removed
1127 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001128extern xmlXPathObjectPtr
1129valuePop(xmlXPathParserContextPtr ctxt)
1130{
1131 xmlXPathObjectPtr ret;
1132
Daniel Veillarda82b1822004-11-08 16:24:57 +00001133 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard1c732d22002-11-30 11:22:59 +00001134 return (0);
1135 ctxt->valueNr--;
1136 if (ctxt->valueNr > 0)
1137 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1138 else
1139 ctxt->value = NULL;
1140 ret = ctxt->valueTab[ctxt->valueNr];
1141 ctxt->valueTab[ctxt->valueNr] = 0;
1142 return (ret);
1143}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001144/**
1145 * valuePush:
1146 * @ctxt: an XPath evaluation context
1147 * @value: the XPath object
1148 *
1149 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001150 *
1151 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001152 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001153extern int
1154valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1155{
Daniel Veillarda82b1822004-11-08 16:24:57 +00001156 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00001157 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001158 xmlXPathObjectPtr *tmp;
1159
1160 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1161 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00001162 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001163 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00001164 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1165 return (0);
1166 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001167 ctxt->valueMax *= 2;
1168 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00001169 }
1170 ctxt->valueTab[ctxt->valueNr] = value;
1171 ctxt->value = value;
1172 return (ctxt->valueNr++);
1173}
Owen Taylor3473f882001-02-23 17:55:21 +00001174
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001175/**
1176 * xmlXPathPopBoolean:
1177 * @ctxt: an XPath parser context
1178 *
1179 * Pops a boolean from the stack, handling conversion if needed.
1180 * Check error with #xmlXPathCheckError.
1181 *
1182 * Returns the boolean
1183 */
1184int
1185xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1186 xmlXPathObjectPtr obj;
1187 int ret;
1188
1189 obj = valuePop(ctxt);
1190 if (obj == NULL) {
1191 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1192 return(0);
1193 }
William M. Brack08171912003-12-29 02:52:11 +00001194 if (obj->type != XPATH_BOOLEAN)
1195 ret = xmlXPathCastToBoolean(obj);
1196 else
1197 ret = obj->boolval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001198 xmlXPathFreeObject(obj);
1199 return(ret);
1200}
1201
1202/**
1203 * xmlXPathPopNumber:
1204 * @ctxt: an XPath parser context
1205 *
1206 * Pops a number from the stack, handling conversion if needed.
1207 * Check error with #xmlXPathCheckError.
1208 *
1209 * Returns the number
1210 */
1211double
1212xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1213 xmlXPathObjectPtr obj;
1214 double ret;
1215
1216 obj = valuePop(ctxt);
1217 if (obj == NULL) {
1218 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1219 return(0);
1220 }
William M. Brack08171912003-12-29 02:52:11 +00001221 if (obj->type != XPATH_NUMBER)
1222 ret = xmlXPathCastToNumber(obj);
1223 else
1224 ret = obj->floatval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001225 xmlXPathFreeObject(obj);
1226 return(ret);
1227}
1228
1229/**
1230 * xmlXPathPopString:
1231 * @ctxt: an XPath parser context
1232 *
1233 * Pops a string from the stack, handling conversion if needed.
1234 * Check error with #xmlXPathCheckError.
1235 *
1236 * Returns the string
1237 */
1238xmlChar *
1239xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1240 xmlXPathObjectPtr obj;
1241 xmlChar * ret;
1242
1243 obj = valuePop(ctxt);
1244 if (obj == NULL) {
1245 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1246 return(NULL);
1247 }
William M. Brack08171912003-12-29 02:52:11 +00001248 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001249 /* TODO: needs refactoring somewhere else */
1250 if (obj->stringval == ret)
1251 obj->stringval = NULL;
1252 xmlXPathFreeObject(obj);
1253 return(ret);
1254}
1255
1256/**
1257 * xmlXPathPopNodeSet:
1258 * @ctxt: an XPath parser context
1259 *
1260 * Pops a node-set from the stack, handling conversion if needed.
1261 * Check error with #xmlXPathCheckError.
1262 *
1263 * Returns the node-set
1264 */
1265xmlNodeSetPtr
1266xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1267 xmlXPathObjectPtr obj;
1268 xmlNodeSetPtr ret;
1269
Daniel Veillardf2a36f92004-11-08 17:55:01 +00001270 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001271 if (ctxt->value == NULL) {
1272 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1273 return(NULL);
1274 }
1275 if (!xmlXPathStackIsNodeSet(ctxt)) {
1276 xmlXPathSetTypeError(ctxt);
1277 return(NULL);
1278 }
1279 obj = valuePop(ctxt);
1280 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00001281#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00001282 /* to fix memory leak of not clearing obj->user */
1283 if (obj->boolval && obj->user != NULL)
1284 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00001285#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001286 xmlXPathFreeNodeSetList(obj);
1287 return(ret);
1288}
1289
1290/**
1291 * xmlXPathPopExternal:
1292 * @ctxt: an XPath parser context
1293 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001294 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001295 * Check error with #xmlXPathCheckError.
1296 *
1297 * Returns the object
1298 */
1299void *
1300xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1301 xmlXPathObjectPtr obj;
1302 void * ret;
1303
Daniel Veillarda82b1822004-11-08 16:24:57 +00001304 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001305 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1306 return(NULL);
1307 }
1308 if (ctxt->value->type != XPATH_USERS) {
1309 xmlXPathSetTypeError(ctxt);
1310 return(NULL);
1311 }
1312 obj = valuePop(ctxt);
1313 ret = obj->user;
1314 xmlXPathFreeObject(obj);
1315 return(ret);
1316}
1317
Owen Taylor3473f882001-02-23 17:55:21 +00001318/*
1319 * Macros for accessing the content. Those should be used only by the parser,
1320 * and not exported.
1321 *
1322 * Dirty macros, i.e. one need to make assumption on the context to use them
1323 *
1324 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1325 * CUR returns the current xmlChar value, i.e. a 8 bit value
1326 * in ISO-Latin or UTF-8.
1327 * This should be used internally by the parser
1328 * only to compare to ASCII values otherwise it would break when
1329 * running with UTF-8 encoding.
1330 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1331 * to compare on ASCII based substring.
1332 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1333 * strings within the parser.
1334 * CURRENT Returns the current char value, with the full decoding of
1335 * UTF-8 if we are using this mode. It returns an int.
1336 * NEXT Skip to the next character, this does the proper decoding
1337 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1338 * It returns the pointer to the current xmlChar.
1339 */
1340
1341#define CUR (*ctxt->cur)
1342#define SKIP(val) ctxt->cur += (val)
1343#define NXT(val) ctxt->cur[(val)]
1344#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001345#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1346
1347#define COPY_BUF(l,b,i,v) \
1348 if (l == 1) b[i++] = (xmlChar) v; \
1349 else i += xmlCopyChar(l,&b[i],v)
1350
1351#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001352
1353#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001354 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001355
1356#define CURRENT (*ctxt->cur)
1357#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1358
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001359
1360#ifndef DBL_DIG
1361#define DBL_DIG 16
1362#endif
1363#ifndef DBL_EPSILON
1364#define DBL_EPSILON 1E-9
1365#endif
1366
1367#define UPPER_DOUBLE 1E9
1368#define LOWER_DOUBLE 1E-5
1369
1370#define INTEGER_DIGITS DBL_DIG
1371#define FRACTION_DIGITS (DBL_DIG + 1)
1372#define EXPONENT_DIGITS (3 + 2)
1373
1374/**
1375 * xmlXPathFormatNumber:
1376 * @number: number to format
1377 * @buffer: output buffer
1378 * @buffersize: size of output buffer
1379 *
1380 * Convert the number into a string representation.
1381 */
1382static void
1383xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1384{
Daniel Veillardcda96922001-08-21 10:56:31 +00001385 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001386 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001387 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001388 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001389 break;
1390 case -1:
1391 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001392 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001393 break;
1394 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001395 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001396 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001397 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001398 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001399 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001400 } else if (number == ((int) number)) {
1401 char work[30];
1402 char *ptr, *cur;
1403 int res, value = (int) number;
1404
1405 ptr = &buffer[0];
1406 if (value < 0) {
1407 *ptr++ = '-';
1408 value = -value;
1409 }
1410 if (value == 0) {
1411 *ptr++ = '0';
1412 } else {
1413 cur = &work[0];
1414 while (value != 0) {
1415 res = value % 10;
1416 value = value / 10;
1417 *cur++ = '0' + res;
1418 }
1419 cur--;
1420 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1421 *ptr++ = *cur--;
1422 }
1423 }
1424 if (ptr - buffer < buffersize) {
1425 *ptr = 0;
1426 } else if (buffersize > 0) {
1427 ptr--;
1428 *ptr = 0;
1429 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001430 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001431 /* 3 is sign, decimal point, and terminating zero */
1432 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1433 int integer_place, fraction_place;
1434 char *ptr;
1435 char *after_fraction;
1436 double absolute_value;
1437 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001438
Bjorn Reese70a9da52001-04-21 16:57:29 +00001439 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001440
Bjorn Reese70a9da52001-04-21 16:57:29 +00001441 /*
1442 * First choose format - scientific or regular floating point.
1443 * In either case, result is in work, and after_fraction points
1444 * just past the fractional part.
1445 */
1446 if ( ((absolute_value > UPPER_DOUBLE) ||
1447 (absolute_value < LOWER_DOUBLE)) &&
1448 (absolute_value != 0.0) ) {
1449 /* Use scientific notation */
1450 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1451 fraction_place = DBL_DIG - 1;
1452 snprintf(work, sizeof(work),"%*.*e",
1453 integer_place, fraction_place, number);
1454 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001455 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001456 else {
1457 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001458 if (absolute_value > 0.0)
1459 integer_place = 1 + (int)log10(absolute_value);
1460 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001461 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001462 fraction_place = (integer_place > 0)
1463 ? DBL_DIG - integer_place
1464 : DBL_DIG;
1465 size = snprintf(work, sizeof(work), "%0.*f",
1466 fraction_place, number);
1467 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001468 }
1469
Bjorn Reese70a9da52001-04-21 16:57:29 +00001470 /* Remove fractional trailing zeroes */
1471 ptr = after_fraction;
1472 while (*(--ptr) == '0')
1473 ;
1474 if (*ptr != '.')
1475 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001476 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001477
1478 /* Finally copy result back to caller */
1479 size = strlen(work) + 1;
1480 if (size > buffersize) {
1481 work[buffersize - 1] = 0;
1482 size = buffersize;
1483 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001484 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001485 }
1486 break;
1487 }
1488}
1489
Owen Taylor3473f882001-02-23 17:55:21 +00001490
1491/************************************************************************
1492 * *
1493 * Routines to handle NodeSets *
1494 * *
1495 ************************************************************************/
1496
1497/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001498 * xmlXPathOrderDocElems:
1499 * @doc: an input document
1500 *
1501 * Call this routine to speed up XPath computation on static documents.
1502 * This stamps all the element nodes with the document order
1503 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00001504 * field, the value stored is actually - the node number (starting at -1)
1505 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001506 *
William M. Brack08171912003-12-29 02:52:11 +00001507 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001508 * of error.
1509 */
1510long
1511xmlXPathOrderDocElems(xmlDocPtr doc) {
1512 long count = 0;
1513 xmlNodePtr cur;
1514
1515 if (doc == NULL)
1516 return(-1);
1517 cur = doc->children;
1518 while (cur != NULL) {
1519 if (cur->type == XML_ELEMENT_NODE) {
1520 cur->content = (void *) (-(++count));
1521 if (cur->children != NULL) {
1522 cur = cur->children;
1523 continue;
1524 }
1525 }
1526 if (cur->next != NULL) {
1527 cur = cur->next;
1528 continue;
1529 }
1530 do {
1531 cur = cur->parent;
1532 if (cur == NULL)
1533 break;
1534 if (cur == (xmlNodePtr) doc) {
1535 cur = NULL;
1536 break;
1537 }
1538 if (cur->next != NULL) {
1539 cur = cur->next;
1540 break;
1541 }
1542 } while (cur != NULL);
1543 }
1544 return(count);
1545}
1546
1547/**
Owen Taylor3473f882001-02-23 17:55:21 +00001548 * xmlXPathCmpNodes:
1549 * @node1: the first node
1550 * @node2: the second node
1551 *
1552 * Compare two nodes w.r.t document order
1553 *
1554 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00001555 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001556 */
1557int
1558xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1559 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001560 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001561 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001562 xmlNodePtr cur, root;
1563
1564 if ((node1 == NULL) || (node2 == NULL))
1565 return(-2);
1566 /*
1567 * a couple of optimizations which will avoid computations in most cases
1568 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001569 if (node1->type == XML_ATTRIBUTE_NODE) {
1570 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001571 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001572 node1 = node1->parent;
1573 }
1574 if (node2->type == XML_ATTRIBUTE_NODE) {
1575 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001576 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001577 node2 = node2->parent;
1578 }
1579 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001580 if (attr1 == attr2) {
1581 /* not required, but we keep attributes in order */
1582 if (attr1 != 0) {
1583 cur = attrNode2->prev;
1584 while (cur != NULL) {
1585 if (cur == attrNode1)
1586 return (1);
1587 cur = cur->prev;
1588 }
1589 return (-1);
1590 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001591 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001592 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001593 if (attr2 == 1)
1594 return(1);
1595 return(-1);
1596 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001597 if ((node1->type == XML_NAMESPACE_DECL) ||
1598 (node2->type == XML_NAMESPACE_DECL))
1599 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001600 if (node1 == node2->prev)
1601 return(1);
1602 if (node1 == node2->next)
1603 return(-1);
1604
1605 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001606 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001607 */
1608 if ((node1->type == XML_ELEMENT_NODE) &&
1609 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001610 (0 > (long) node1->content) &&
1611 (0 > (long) node2->content) &&
1612 (node1->doc == node2->doc)) {
1613 long l1, l2;
1614
1615 l1 = -((long) node1->content);
1616 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001617 if (l1 < l2)
1618 return(1);
1619 if (l1 > l2)
1620 return(-1);
1621 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001622
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001623 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001624 * compute depth to root
1625 */
1626 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1627 if (cur == node1)
1628 return(1);
1629 depth2++;
1630 }
1631 root = cur;
1632 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1633 if (cur == node2)
1634 return(-1);
1635 depth1++;
1636 }
1637 /*
1638 * Distinct document (or distinct entities :-( ) case.
1639 */
1640 if (root != cur) {
1641 return(-2);
1642 }
1643 /*
1644 * get the nearest common ancestor.
1645 */
1646 while (depth1 > depth2) {
1647 depth1--;
1648 node1 = node1->parent;
1649 }
1650 while (depth2 > depth1) {
1651 depth2--;
1652 node2 = node2->parent;
1653 }
1654 while (node1->parent != node2->parent) {
1655 node1 = node1->parent;
1656 node2 = node2->parent;
1657 /* should not happen but just in case ... */
1658 if ((node1 == NULL) || (node2 == NULL))
1659 return(-2);
1660 }
1661 /*
1662 * Find who's first.
1663 */
Daniel Veillardf49be472004-02-17 11:48:18 +00001664 if (node1 == node2->prev)
1665 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001666 if (node1 == node2->next)
1667 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00001668 /*
1669 * Speedup using document order if availble.
1670 */
1671 if ((node1->type == XML_ELEMENT_NODE) &&
1672 (node2->type == XML_ELEMENT_NODE) &&
1673 (0 > (long) node1->content) &&
1674 (0 > (long) node2->content) &&
1675 (node1->doc == node2->doc)) {
1676 long l1, l2;
1677
1678 l1 = -((long) node1->content);
1679 l2 = -((long) node2->content);
1680 if (l1 < l2)
1681 return(1);
1682 if (l1 > l2)
1683 return(-1);
1684 }
1685
Owen Taylor3473f882001-02-23 17:55:21 +00001686 for (cur = node1->next;cur != NULL;cur = cur->next)
1687 if (cur == node2)
1688 return(1);
1689 return(-1); /* assume there is no sibling list corruption */
1690}
1691
1692/**
1693 * xmlXPathNodeSetSort:
1694 * @set: the node set
1695 *
1696 * Sort the node set in document order
1697 */
1698void
1699xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001700 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001701 xmlNodePtr tmp;
1702
1703 if (set == NULL)
1704 return;
1705
1706 /* Use Shell's sort to sort the node-set */
1707 len = set->nodeNr;
1708 for (incr = len / 2; incr > 0; incr /= 2) {
1709 for (i = incr; i < len; i++) {
1710 j = i - incr;
1711 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001712 if (xmlXPathCmpNodes(set->nodeTab[j],
1713 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001714 tmp = set->nodeTab[j];
1715 set->nodeTab[j] = set->nodeTab[j + incr];
1716 set->nodeTab[j + incr] = tmp;
1717 j -= incr;
1718 } else
1719 break;
1720 }
1721 }
1722 }
1723}
1724
1725#define XML_NODESET_DEFAULT 10
1726/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001727 * xmlXPathNodeSetDupNs:
1728 * @node: the parent node of the namespace XPath node
1729 * @ns: the libxml namespace declaration node.
1730 *
1731 * Namespace node in libxml don't match the XPath semantic. In a node set
1732 * the namespace nodes are duplicated and the next pointer is set to the
1733 * parent node in the XPath semantic.
1734 *
1735 * Returns the newly created object.
1736 */
1737static xmlNodePtr
1738xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1739 xmlNsPtr cur;
1740
1741 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1742 return(NULL);
1743 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1744 return((xmlNodePtr) ns);
1745
1746 /*
1747 * Allocate a new Namespace and fill the fields.
1748 */
1749 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1750 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001751 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001752 return(NULL);
1753 }
1754 memset(cur, 0, sizeof(xmlNs));
1755 cur->type = XML_NAMESPACE_DECL;
1756 if (ns->href != NULL)
1757 cur->href = xmlStrdup(ns->href);
1758 if (ns->prefix != NULL)
1759 cur->prefix = xmlStrdup(ns->prefix);
1760 cur->next = (xmlNsPtr) node;
1761 return((xmlNodePtr) cur);
1762}
1763
1764/**
1765 * xmlXPathNodeSetFreeNs:
1766 * @ns: the XPath namespace node found in a nodeset.
1767 *
William M. Brack08171912003-12-29 02:52:11 +00001768 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001769 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00001770 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001771 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001772void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001773xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1774 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1775 return;
1776
1777 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1778 if (ns->href != NULL)
1779 xmlFree((xmlChar *)ns->href);
1780 if (ns->prefix != NULL)
1781 xmlFree((xmlChar *)ns->prefix);
1782 xmlFree(ns);
1783 }
1784}
1785
1786/**
Owen Taylor3473f882001-02-23 17:55:21 +00001787 * xmlXPathNodeSetCreate:
1788 * @val: an initial xmlNodePtr, or NULL
1789 *
1790 * Create a new xmlNodeSetPtr of type double and of value @val
1791 *
1792 * Returns the newly created object.
1793 */
1794xmlNodeSetPtr
1795xmlXPathNodeSetCreate(xmlNodePtr val) {
1796 xmlNodeSetPtr ret;
1797
1798 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1799 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001800 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001801 return(NULL);
1802 }
1803 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1804 if (val != NULL) {
1805 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1806 sizeof(xmlNodePtr));
1807 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001808 xmlXPathErrMemory(NULL, "creating nodeset\n");
1809 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001810 return(NULL);
1811 }
1812 memset(ret->nodeTab, 0 ,
1813 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1814 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001815 if (val->type == XML_NAMESPACE_DECL) {
1816 xmlNsPtr ns = (xmlNsPtr) val;
1817
1818 ret->nodeTab[ret->nodeNr++] =
1819 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1820 } else
1821 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001822 }
1823 return(ret);
1824}
1825
1826/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001827 * xmlXPathNodeSetContains:
1828 * @cur: the node-set
1829 * @val: the node
1830 *
1831 * checks whether @cur contains @val
1832 *
1833 * Returns true (1) if @cur contains @val, false (0) otherwise
1834 */
1835int
1836xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1837 int i;
1838
Daniel Veillarda82b1822004-11-08 16:24:57 +00001839 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001840 if (val->type == XML_NAMESPACE_DECL) {
1841 for (i = 0; i < cur->nodeNr; i++) {
1842 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1843 xmlNsPtr ns1, ns2;
1844
1845 ns1 = (xmlNsPtr) val;
1846 ns2 = (xmlNsPtr) cur->nodeTab[i];
1847 if (ns1 == ns2)
1848 return(1);
1849 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1850 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1851 return(1);
1852 }
1853 }
1854 } else {
1855 for (i = 0; i < cur->nodeNr; i++) {
1856 if (cur->nodeTab[i] == val)
1857 return(1);
1858 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001859 }
1860 return(0);
1861}
1862
1863/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001864 * xmlXPathNodeSetAddNs:
1865 * @cur: the initial node set
1866 * @node: the hosting node
1867 * @ns: a the namespace node
1868 *
1869 * add a new namespace node to an existing NodeSet
1870 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001871void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001872xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1873 int i;
1874
Daniel Veillarda82b1822004-11-08 16:24:57 +00001875
1876 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
1877 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001878 (node->type != XML_ELEMENT_NODE))
1879 return;
1880
William M. Brack08171912003-12-29 02:52:11 +00001881 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001882 /*
William M. Brack08171912003-12-29 02:52:11 +00001883 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001884 */
1885 for (i = 0;i < cur->nodeNr;i++) {
1886 if ((cur->nodeTab[i] != NULL) &&
1887 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001888 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001889 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1890 return;
1891 }
1892
1893 /*
1894 * grow the nodeTab if needed
1895 */
1896 if (cur->nodeMax == 0) {
1897 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1898 sizeof(xmlNodePtr));
1899 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001900 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001901 return;
1902 }
1903 memset(cur->nodeTab, 0 ,
1904 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1905 cur->nodeMax = XML_NODESET_DEFAULT;
1906 } else if (cur->nodeNr == cur->nodeMax) {
1907 xmlNodePtr *temp;
1908
1909 cur->nodeMax *= 2;
1910 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1911 sizeof(xmlNodePtr));
1912 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001913 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001914 return;
1915 }
1916 cur->nodeTab = temp;
1917 }
1918 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1919}
1920
1921/**
Owen Taylor3473f882001-02-23 17:55:21 +00001922 * xmlXPathNodeSetAdd:
1923 * @cur: the initial node set
1924 * @val: a new xmlNodePtr
1925 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001926 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001927 */
1928void
1929xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1930 int i;
1931
Daniel Veillarda82b1822004-11-08 16:24:57 +00001932 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001933
Daniel Veillardef0b4502003-03-24 13:57:34 +00001934#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001935 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1936 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001937#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001938
William M. Brack08171912003-12-29 02:52:11 +00001939 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001940 /*
William M. Brack08171912003-12-29 02:52:11 +00001941 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00001942 */
1943 for (i = 0;i < cur->nodeNr;i++)
1944 if (cur->nodeTab[i] == val) return;
1945
1946 /*
1947 * grow the nodeTab if needed
1948 */
1949 if (cur->nodeMax == 0) {
1950 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1951 sizeof(xmlNodePtr));
1952 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001953 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001954 return;
1955 }
1956 memset(cur->nodeTab, 0 ,
1957 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1958 cur->nodeMax = XML_NODESET_DEFAULT;
1959 } else if (cur->nodeNr == cur->nodeMax) {
1960 xmlNodePtr *temp;
1961
1962 cur->nodeMax *= 2;
1963 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1964 sizeof(xmlNodePtr));
1965 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001966 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001967 return;
1968 }
1969 cur->nodeTab = temp;
1970 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001971 if (val->type == XML_NAMESPACE_DECL) {
1972 xmlNsPtr ns = (xmlNsPtr) val;
1973
1974 cur->nodeTab[cur->nodeNr++] =
1975 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1976 } else
1977 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001978}
1979
1980/**
1981 * xmlXPathNodeSetAddUnique:
1982 * @cur: the initial node set
1983 * @val: a new xmlNodePtr
1984 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001985 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001986 * when we are sure the node is not already in the set.
1987 */
1988void
1989xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00001990 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001991
Daniel Veillardef0b4502003-03-24 13:57:34 +00001992#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001993 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1994 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001995#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001996
William M. Brack08171912003-12-29 02:52:11 +00001997 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001998 /*
1999 * grow the nodeTab if needed
2000 */
2001 if (cur->nodeMax == 0) {
2002 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2003 sizeof(xmlNodePtr));
2004 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002005 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002006 return;
2007 }
2008 memset(cur->nodeTab, 0 ,
2009 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2010 cur->nodeMax = XML_NODESET_DEFAULT;
2011 } else if (cur->nodeNr == cur->nodeMax) {
2012 xmlNodePtr *temp;
2013
2014 cur->nodeMax *= 2;
2015 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
2016 sizeof(xmlNodePtr));
2017 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002018 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002019 return;
2020 }
2021 cur->nodeTab = temp;
2022 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002023 if (val->type == XML_NAMESPACE_DECL) {
2024 xmlNsPtr ns = (xmlNsPtr) val;
2025
2026 cur->nodeTab[cur->nodeNr++] =
2027 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2028 } else
2029 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00002030}
2031
2032/**
2033 * xmlXPathNodeSetMerge:
2034 * @val1: the first NodeSet or NULL
2035 * @val2: the second NodeSet
2036 *
2037 * Merges two nodesets, all nodes from @val2 are added to @val1
2038 * if @val1 is NULL, a new set is created and copied from @val2
2039 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002040 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002041 */
2042xmlNodeSetPtr
2043xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002044 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00002045
2046 if (val2 == NULL) return(val1);
2047 if (val1 == NULL) {
2048 val1 = xmlXPathNodeSetCreate(NULL);
2049 }
2050
William M. Brack08171912003-12-29 02:52:11 +00002051 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002052 initNr = val1->nodeNr;
2053
2054 for (i = 0;i < val2->nodeNr;i++) {
2055 /*
William M. Brack08171912003-12-29 02:52:11 +00002056 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00002057 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002058 skip = 0;
2059 for (j = 0; j < initNr; j++) {
2060 if (val1->nodeTab[j] == val2->nodeTab[i]) {
2061 skip = 1;
2062 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002063 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
2064 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
2065 xmlNsPtr ns1, ns2;
2066 ns1 = (xmlNsPtr) val1->nodeTab[j];
2067 ns2 = (xmlNsPtr) val2->nodeTab[i];
2068 if ((ns1->next == ns2->next) &&
2069 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
2070 skip = 1;
2071 break;
2072 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002073 }
2074 }
2075 if (skip)
2076 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00002077
2078 /*
2079 * grow the nodeTab if needed
2080 */
2081 if (val1->nodeMax == 0) {
2082 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2083 sizeof(xmlNodePtr));
2084 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002085 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002086 return(NULL);
2087 }
2088 memset(val1->nodeTab, 0 ,
2089 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2090 val1->nodeMax = XML_NODESET_DEFAULT;
2091 } else if (val1->nodeNr == val1->nodeMax) {
2092 xmlNodePtr *temp;
2093
2094 val1->nodeMax *= 2;
2095 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2096 sizeof(xmlNodePtr));
2097 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002098 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002099 return(NULL);
2100 }
2101 val1->nodeTab = temp;
2102 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002103 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2104 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2105
2106 val1->nodeTab[val1->nodeNr++] =
2107 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2108 } else
2109 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002110 }
2111
2112 return(val1);
2113}
2114
2115/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002116 * xmlXPathNodeSetMergeUnique:
2117 * @val1: the first NodeSet or NULL
2118 * @val2: the second NodeSet
2119 *
2120 * Merges two nodesets, all nodes from @val2 are added to @val1
2121 * if @val1 is NULL, a new set is created and copied from @val2
2122 *
2123 * Returns @val1 once extended or NULL in case of error.
2124 */
2125static xmlNodeSetPtr
2126xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002127 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002128
2129 if (val2 == NULL) return(val1);
2130 if (val1 == NULL) {
2131 val1 = xmlXPathNodeSetCreate(NULL);
2132 }
2133
William M. Brack08171912003-12-29 02:52:11 +00002134 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002135
2136 for (i = 0;i < val2->nodeNr;i++) {
2137 /*
2138 * grow the nodeTab if needed
2139 */
2140 if (val1->nodeMax == 0) {
2141 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2142 sizeof(xmlNodePtr));
2143 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002144 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002145 return(NULL);
2146 }
2147 memset(val1->nodeTab, 0 ,
2148 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2149 val1->nodeMax = XML_NODESET_DEFAULT;
2150 } else if (val1->nodeNr == val1->nodeMax) {
2151 xmlNodePtr *temp;
2152
2153 val1->nodeMax *= 2;
2154 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2155 sizeof(xmlNodePtr));
2156 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002157 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002158 return(NULL);
2159 }
2160 val1->nodeTab = temp;
2161 }
2162 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2163 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2164
2165 val1->nodeTab[val1->nodeNr++] =
2166 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2167 } else
2168 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2169 }
2170
2171 return(val1);
2172}
2173
2174/**
Owen Taylor3473f882001-02-23 17:55:21 +00002175 * xmlXPathNodeSetDel:
2176 * @cur: the initial node set
2177 * @val: an xmlNodePtr
2178 *
2179 * Removes an xmlNodePtr from an existing NodeSet
2180 */
2181void
2182xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2183 int i;
2184
2185 if (cur == NULL) return;
2186 if (val == NULL) return;
2187
2188 /*
William M. Brack08171912003-12-29 02:52:11 +00002189 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002190 */
2191 for (i = 0;i < cur->nodeNr;i++)
2192 if (cur->nodeTab[i] == val) break;
2193
William M. Brack08171912003-12-29 02:52:11 +00002194 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002195#ifdef DEBUG
2196 xmlGenericError(xmlGenericErrorContext,
2197 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2198 val->name);
2199#endif
2200 return;
2201 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002202 if ((cur->nodeTab[i] != NULL) &&
2203 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2204 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002205 cur->nodeNr--;
2206 for (;i < cur->nodeNr;i++)
2207 cur->nodeTab[i] = cur->nodeTab[i + 1];
2208 cur->nodeTab[cur->nodeNr] = NULL;
2209}
2210
2211/**
2212 * xmlXPathNodeSetRemove:
2213 * @cur: the initial node set
2214 * @val: the index to remove
2215 *
2216 * Removes an entry from an existing NodeSet list.
2217 */
2218void
2219xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2220 if (cur == NULL) return;
2221 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002222 if ((cur->nodeTab[val] != NULL) &&
2223 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2224 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002225 cur->nodeNr--;
2226 for (;val < cur->nodeNr;val++)
2227 cur->nodeTab[val] = cur->nodeTab[val + 1];
2228 cur->nodeTab[cur->nodeNr] = NULL;
2229}
2230
2231/**
2232 * xmlXPathFreeNodeSet:
2233 * @obj: the xmlNodeSetPtr to free
2234 *
2235 * Free the NodeSet compound (not the actual nodes !).
2236 */
2237void
2238xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2239 if (obj == NULL) return;
2240 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002241 int i;
2242
William M. Brack08171912003-12-29 02:52:11 +00002243 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002244 for (i = 0;i < obj->nodeNr;i++)
2245 if ((obj->nodeTab[i] != NULL) &&
2246 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2247 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002248 xmlFree(obj->nodeTab);
2249 }
Owen Taylor3473f882001-02-23 17:55:21 +00002250 xmlFree(obj);
2251}
2252
2253/**
2254 * xmlXPathFreeValueTree:
2255 * @obj: the xmlNodeSetPtr to free
2256 *
2257 * Free the NodeSet compound and the actual tree, this is different
2258 * from xmlXPathFreeNodeSet()
2259 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002260static void
Owen Taylor3473f882001-02-23 17:55:21 +00002261xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2262 int i;
2263
2264 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002265
2266 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002267 for (i = 0;i < obj->nodeNr;i++) {
2268 if (obj->nodeTab[i] != NULL) {
2269 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2270 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2271 } else {
2272 xmlFreeNodeList(obj->nodeTab[i]);
2273 }
2274 }
2275 }
Owen Taylor3473f882001-02-23 17:55:21 +00002276 xmlFree(obj->nodeTab);
2277 }
Owen Taylor3473f882001-02-23 17:55:21 +00002278 xmlFree(obj);
2279}
2280
2281#if defined(DEBUG) || defined(DEBUG_STEP)
2282/**
2283 * xmlGenericErrorContextNodeSet:
2284 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002285 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002286 *
2287 * Quick display of a NodeSet
2288 */
2289void
2290xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2291 int i;
2292
2293 if (output == NULL) output = xmlGenericErrorContext;
2294 if (obj == NULL) {
2295 fprintf(output, "NodeSet == NULL !\n");
2296 return;
2297 }
2298 if (obj->nodeNr == 0) {
2299 fprintf(output, "NodeSet is empty\n");
2300 return;
2301 }
2302 if (obj->nodeTab == NULL) {
2303 fprintf(output, " nodeTab == NULL !\n");
2304 return;
2305 }
2306 for (i = 0; i < obj->nodeNr; i++) {
2307 if (obj->nodeTab[i] == NULL) {
2308 fprintf(output, " NULL !\n");
2309 return;
2310 }
2311 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2312 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2313 fprintf(output, " /");
2314 else if (obj->nodeTab[i]->name == NULL)
2315 fprintf(output, " noname!");
2316 else fprintf(output, " %s", obj->nodeTab[i]->name);
2317 }
2318 fprintf(output, "\n");
2319}
2320#endif
2321
2322/**
2323 * xmlXPathNewNodeSet:
2324 * @val: the NodePtr value
2325 *
2326 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2327 * it with the single Node @val
2328 *
2329 * Returns the newly created object.
2330 */
2331xmlXPathObjectPtr
2332xmlXPathNewNodeSet(xmlNodePtr val) {
2333 xmlXPathObjectPtr ret;
2334
2335 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2336 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002337 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002338 return(NULL);
2339 }
2340 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2341 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002342 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002343 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002344 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002345 return(ret);
2346}
2347
2348/**
2349 * xmlXPathNewValueTree:
2350 * @val: the NodePtr value
2351 *
2352 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2353 * it with the tree root @val
2354 *
2355 * Returns the newly created object.
2356 */
2357xmlXPathObjectPtr
2358xmlXPathNewValueTree(xmlNodePtr val) {
2359 xmlXPathObjectPtr ret;
2360
2361 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2362 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002363 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002364 return(NULL);
2365 }
2366 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2367 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002368 ret->boolval = 1;
2369 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002370 ret->nodesetval = xmlXPathNodeSetCreate(val);
2371 return(ret);
2372}
2373
2374/**
2375 * xmlXPathNewNodeSetList:
2376 * @val: an existing NodeSet
2377 *
2378 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2379 * it with the Nodeset @val
2380 *
2381 * Returns the newly created object.
2382 */
2383xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002384xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2385{
Owen Taylor3473f882001-02-23 17:55:21 +00002386 xmlXPathObjectPtr ret;
2387 int i;
2388
2389 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002390 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002391 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002392 ret = xmlXPathNewNodeSet(NULL);
2393 else {
2394 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2395 for (i = 1; i < val->nodeNr; ++i)
2396 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2397 }
Owen Taylor3473f882001-02-23 17:55:21 +00002398
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002399 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002400}
2401
2402/**
2403 * xmlXPathWrapNodeSet:
2404 * @val: the NodePtr value
2405 *
2406 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2407 *
2408 * Returns the newly created object.
2409 */
2410xmlXPathObjectPtr
2411xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2412 xmlXPathObjectPtr ret;
2413
2414 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2415 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002416 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002417 return(NULL);
2418 }
2419 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2420 ret->type = XPATH_NODESET;
2421 ret->nodesetval = val;
2422 return(ret);
2423}
2424
2425/**
2426 * xmlXPathFreeNodeSetList:
2427 * @obj: an existing NodeSetList object
2428 *
2429 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2430 * the list contrary to xmlXPathFreeObject().
2431 */
2432void
2433xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2434 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002435 xmlFree(obj);
2436}
2437
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002438/**
2439 * xmlXPathDifference:
2440 * @nodes1: a node-set
2441 * @nodes2: a node-set
2442 *
2443 * Implements the EXSLT - Sets difference() function:
2444 * node-set set:difference (node-set, node-set)
2445 *
2446 * Returns the difference between the two node sets, or nodes1 if
2447 * nodes2 is empty
2448 */
2449xmlNodeSetPtr
2450xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2451 xmlNodeSetPtr ret;
2452 int i, l1;
2453 xmlNodePtr cur;
2454
2455 if (xmlXPathNodeSetIsEmpty(nodes2))
2456 return(nodes1);
2457
2458 ret = xmlXPathNodeSetCreate(NULL);
2459 if (xmlXPathNodeSetIsEmpty(nodes1))
2460 return(ret);
2461
2462 l1 = xmlXPathNodeSetGetLength(nodes1);
2463
2464 for (i = 0; i < l1; i++) {
2465 cur = xmlXPathNodeSetItem(nodes1, i);
2466 if (!xmlXPathNodeSetContains(nodes2, cur))
2467 xmlXPathNodeSetAddUnique(ret, cur);
2468 }
2469 return(ret);
2470}
2471
2472/**
2473 * xmlXPathIntersection:
2474 * @nodes1: a node-set
2475 * @nodes2: a node-set
2476 *
2477 * Implements the EXSLT - Sets intersection() function:
2478 * node-set set:intersection (node-set, node-set)
2479 *
2480 * Returns a node set comprising the nodes that are within both the
2481 * node sets passed as arguments
2482 */
2483xmlNodeSetPtr
2484xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2485 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2486 int i, l1;
2487 xmlNodePtr cur;
2488
2489 if (xmlXPathNodeSetIsEmpty(nodes1))
2490 return(ret);
2491 if (xmlXPathNodeSetIsEmpty(nodes2))
2492 return(ret);
2493
2494 l1 = xmlXPathNodeSetGetLength(nodes1);
2495
2496 for (i = 0; i < l1; i++) {
2497 cur = xmlXPathNodeSetItem(nodes1, i);
2498 if (xmlXPathNodeSetContains(nodes2, cur))
2499 xmlXPathNodeSetAddUnique(ret, cur);
2500 }
2501 return(ret);
2502}
2503
2504/**
2505 * xmlXPathDistinctSorted:
2506 * @nodes: a node-set, sorted by document order
2507 *
2508 * Implements the EXSLT - Sets distinct() function:
2509 * node-set set:distinct (node-set)
2510 *
2511 * Returns a subset of the nodes contained in @nodes, or @nodes if
2512 * it is empty
2513 */
2514xmlNodeSetPtr
2515xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2516 xmlNodeSetPtr ret;
2517 xmlHashTablePtr hash;
2518 int i, l;
2519 xmlChar * strval;
2520 xmlNodePtr cur;
2521
2522 if (xmlXPathNodeSetIsEmpty(nodes))
2523 return(nodes);
2524
2525 ret = xmlXPathNodeSetCreate(NULL);
2526 l = xmlXPathNodeSetGetLength(nodes);
2527 hash = xmlHashCreate (l);
2528 for (i = 0; i < l; i++) {
2529 cur = xmlXPathNodeSetItem(nodes, i);
2530 strval = xmlXPathCastNodeToString(cur);
2531 if (xmlHashLookup(hash, strval) == NULL) {
2532 xmlHashAddEntry(hash, strval, strval);
2533 xmlXPathNodeSetAddUnique(ret, cur);
2534 } else {
2535 xmlFree(strval);
2536 }
2537 }
2538 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2539 return(ret);
2540}
2541
2542/**
2543 * xmlXPathDistinct:
2544 * @nodes: a node-set
2545 *
2546 * Implements the EXSLT - Sets distinct() function:
2547 * node-set set:distinct (node-set)
2548 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2549 * is called with the sorted node-set
2550 *
2551 * Returns a subset of the nodes contained in @nodes, or @nodes if
2552 * it is empty
2553 */
2554xmlNodeSetPtr
2555xmlXPathDistinct (xmlNodeSetPtr nodes) {
2556 if (xmlXPathNodeSetIsEmpty(nodes))
2557 return(nodes);
2558
2559 xmlXPathNodeSetSort(nodes);
2560 return(xmlXPathDistinctSorted(nodes));
2561}
2562
2563/**
2564 * xmlXPathHasSameNodes:
2565 * @nodes1: a node-set
2566 * @nodes2: a node-set
2567 *
2568 * Implements the EXSLT - Sets has-same-nodes function:
2569 * boolean set:has-same-node(node-set, node-set)
2570 *
2571 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2572 * otherwise
2573 */
2574int
2575xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2576 int i, l;
2577 xmlNodePtr cur;
2578
2579 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2580 xmlXPathNodeSetIsEmpty(nodes2))
2581 return(0);
2582
2583 l = xmlXPathNodeSetGetLength(nodes1);
2584 for (i = 0; i < l; i++) {
2585 cur = xmlXPathNodeSetItem(nodes1, i);
2586 if (xmlXPathNodeSetContains(nodes2, cur))
2587 return(1);
2588 }
2589 return(0);
2590}
2591
2592/**
2593 * xmlXPathNodeLeadingSorted:
2594 * @nodes: a node-set, sorted by document order
2595 * @node: a node
2596 *
2597 * Implements the EXSLT - Sets leading() function:
2598 * node-set set:leading (node-set, node-set)
2599 *
2600 * Returns the nodes in @nodes that precede @node in document order,
2601 * @nodes if @node is NULL or an empty node-set if @nodes
2602 * doesn't contain @node
2603 */
2604xmlNodeSetPtr
2605xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2606 int i, l;
2607 xmlNodePtr cur;
2608 xmlNodeSetPtr ret;
2609
2610 if (node == NULL)
2611 return(nodes);
2612
2613 ret = xmlXPathNodeSetCreate(NULL);
2614 if (xmlXPathNodeSetIsEmpty(nodes) ||
2615 (!xmlXPathNodeSetContains(nodes, node)))
2616 return(ret);
2617
2618 l = xmlXPathNodeSetGetLength(nodes);
2619 for (i = 0; i < l; i++) {
2620 cur = xmlXPathNodeSetItem(nodes, i);
2621 if (cur == node)
2622 break;
2623 xmlXPathNodeSetAddUnique(ret, cur);
2624 }
2625 return(ret);
2626}
2627
2628/**
2629 * xmlXPathNodeLeading:
2630 * @nodes: a node-set
2631 * @node: a node
2632 *
2633 * Implements the EXSLT - Sets leading() function:
2634 * node-set set:leading (node-set, node-set)
2635 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2636 * is called.
2637 *
2638 * Returns the nodes in @nodes that precede @node in document order,
2639 * @nodes if @node is NULL or an empty node-set if @nodes
2640 * doesn't contain @node
2641 */
2642xmlNodeSetPtr
2643xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2644 xmlXPathNodeSetSort(nodes);
2645 return(xmlXPathNodeLeadingSorted(nodes, node));
2646}
2647
2648/**
2649 * xmlXPathLeadingSorted:
2650 * @nodes1: a node-set, sorted by document order
2651 * @nodes2: a node-set, sorted by document order
2652 *
2653 * Implements the EXSLT - Sets leading() function:
2654 * node-set set:leading (node-set, node-set)
2655 *
2656 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2657 * in document order, @nodes1 if @nodes2 is NULL or empty or
2658 * an empty node-set if @nodes1 doesn't contain @nodes2
2659 */
2660xmlNodeSetPtr
2661xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2662 if (xmlXPathNodeSetIsEmpty(nodes2))
2663 return(nodes1);
2664 return(xmlXPathNodeLeadingSorted(nodes1,
2665 xmlXPathNodeSetItem(nodes2, 1)));
2666}
2667
2668/**
2669 * xmlXPathLeading:
2670 * @nodes1: a node-set
2671 * @nodes2: a node-set
2672 *
2673 * Implements the EXSLT - Sets leading() function:
2674 * node-set set:leading (node-set, node-set)
2675 * @nodes1 and @nodes2 are sorted by document order, then
2676 * #exslSetsLeadingSorted is called.
2677 *
2678 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2679 * in document order, @nodes1 if @nodes2 is NULL or empty or
2680 * an empty node-set if @nodes1 doesn't contain @nodes2
2681 */
2682xmlNodeSetPtr
2683xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2684 if (xmlXPathNodeSetIsEmpty(nodes2))
2685 return(nodes1);
2686 if (xmlXPathNodeSetIsEmpty(nodes1))
2687 return(xmlXPathNodeSetCreate(NULL));
2688 xmlXPathNodeSetSort(nodes1);
2689 xmlXPathNodeSetSort(nodes2);
2690 return(xmlXPathNodeLeadingSorted(nodes1,
2691 xmlXPathNodeSetItem(nodes2, 1)));
2692}
2693
2694/**
2695 * xmlXPathNodeTrailingSorted:
2696 * @nodes: a node-set, sorted by document order
2697 * @node: a node
2698 *
2699 * Implements the EXSLT - Sets trailing() function:
2700 * node-set set:trailing (node-set, node-set)
2701 *
2702 * Returns the nodes in @nodes that follow @node in document order,
2703 * @nodes if @node is NULL or an empty node-set if @nodes
2704 * doesn't contain @node
2705 */
2706xmlNodeSetPtr
2707xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2708 int i, l;
2709 xmlNodePtr cur;
2710 xmlNodeSetPtr ret;
2711
2712 if (node == NULL)
2713 return(nodes);
2714
2715 ret = xmlXPathNodeSetCreate(NULL);
2716 if (xmlXPathNodeSetIsEmpty(nodes) ||
2717 (!xmlXPathNodeSetContains(nodes, node)))
2718 return(ret);
2719
2720 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002721 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002722 cur = xmlXPathNodeSetItem(nodes, i);
2723 if (cur == node)
2724 break;
2725 xmlXPathNodeSetAddUnique(ret, cur);
2726 }
2727 return(ret);
2728}
2729
2730/**
2731 * xmlXPathNodeTrailing:
2732 * @nodes: a node-set
2733 * @node: a node
2734 *
2735 * Implements the EXSLT - Sets trailing() function:
2736 * node-set set:trailing (node-set, node-set)
2737 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2738 * is called.
2739 *
2740 * Returns the nodes in @nodes that follow @node in document order,
2741 * @nodes if @node is NULL or an empty node-set if @nodes
2742 * doesn't contain @node
2743 */
2744xmlNodeSetPtr
2745xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2746 xmlXPathNodeSetSort(nodes);
2747 return(xmlXPathNodeTrailingSorted(nodes, node));
2748}
2749
2750/**
2751 * xmlXPathTrailingSorted:
2752 * @nodes1: a node-set, sorted by document order
2753 * @nodes2: a node-set, sorted by document order
2754 *
2755 * Implements the EXSLT - Sets trailing() function:
2756 * node-set set:trailing (node-set, node-set)
2757 *
2758 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2759 * in document order, @nodes1 if @nodes2 is NULL or empty or
2760 * an empty node-set if @nodes1 doesn't contain @nodes2
2761 */
2762xmlNodeSetPtr
2763xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2764 if (xmlXPathNodeSetIsEmpty(nodes2))
2765 return(nodes1);
2766 return(xmlXPathNodeTrailingSorted(nodes1,
2767 xmlXPathNodeSetItem(nodes2, 0)));
2768}
2769
2770/**
2771 * xmlXPathTrailing:
2772 * @nodes1: a node-set
2773 * @nodes2: a node-set
2774 *
2775 * Implements the EXSLT - Sets trailing() function:
2776 * node-set set:trailing (node-set, node-set)
2777 * @nodes1 and @nodes2 are sorted by document order, then
2778 * #xmlXPathTrailingSorted is called.
2779 *
2780 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2781 * in document order, @nodes1 if @nodes2 is NULL or empty or
2782 * an empty node-set if @nodes1 doesn't contain @nodes2
2783 */
2784xmlNodeSetPtr
2785xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2786 if (xmlXPathNodeSetIsEmpty(nodes2))
2787 return(nodes1);
2788 if (xmlXPathNodeSetIsEmpty(nodes1))
2789 return(xmlXPathNodeSetCreate(NULL));
2790 xmlXPathNodeSetSort(nodes1);
2791 xmlXPathNodeSetSort(nodes2);
2792 return(xmlXPathNodeTrailingSorted(nodes1,
2793 xmlXPathNodeSetItem(nodes2, 0)));
2794}
2795
Owen Taylor3473f882001-02-23 17:55:21 +00002796/************************************************************************
2797 * *
2798 * Routines to handle extra functions *
2799 * *
2800 ************************************************************************/
2801
2802/**
2803 * xmlXPathRegisterFunc:
2804 * @ctxt: the XPath context
2805 * @name: the function name
2806 * @f: the function implementation or NULL
2807 *
2808 * Register a new function. If @f is NULL it unregisters the function
2809 *
2810 * Returns 0 in case of success, -1 in case of error
2811 */
2812int
2813xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2814 xmlXPathFunction f) {
2815 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2816}
2817
2818/**
2819 * xmlXPathRegisterFuncNS:
2820 * @ctxt: the XPath context
2821 * @name: the function name
2822 * @ns_uri: the function namespace URI
2823 * @f: the function implementation or NULL
2824 *
2825 * Register a new function. If @f is NULL it unregisters the function
2826 *
2827 * Returns 0 in case of success, -1 in case of error
2828 */
2829int
2830xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2831 const xmlChar *ns_uri, xmlXPathFunction f) {
2832 if (ctxt == NULL)
2833 return(-1);
2834 if (name == NULL)
2835 return(-1);
2836
2837 if (ctxt->funcHash == NULL)
2838 ctxt->funcHash = xmlHashCreate(0);
2839 if (ctxt->funcHash == NULL)
2840 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002841 if (f == NULL)
2842 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00002843 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00002844}
2845
2846/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002847 * xmlXPathRegisterFuncLookup:
2848 * @ctxt: the XPath context
2849 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002850 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002851 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002852 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002853 */
2854void
2855xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2856 xmlXPathFuncLookupFunc f,
2857 void *funcCtxt) {
2858 if (ctxt == NULL)
2859 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002860 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002861 ctxt->funcLookupData = funcCtxt;
2862}
2863
2864/**
Owen Taylor3473f882001-02-23 17:55:21 +00002865 * xmlXPathFunctionLookup:
2866 * @ctxt: the XPath context
2867 * @name: the function name
2868 *
2869 * Search in the Function array of the context for the given
2870 * function.
2871 *
2872 * Returns the xmlXPathFunction or NULL if not found
2873 */
2874xmlXPathFunction
2875xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002876 if (ctxt == NULL)
2877 return (NULL);
2878
2879 if (ctxt->funcLookupFunc != NULL) {
2880 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002881 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002882
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002883 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002884 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002885 if (ret != NULL)
2886 return(ret);
2887 }
Owen Taylor3473f882001-02-23 17:55:21 +00002888 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2889}
2890
2891/**
2892 * xmlXPathFunctionLookupNS:
2893 * @ctxt: the XPath context
2894 * @name: the function name
2895 * @ns_uri: the function namespace URI
2896 *
2897 * Search in the Function array of the context for the given
2898 * function.
2899 *
2900 * Returns the xmlXPathFunction or NULL if not found
2901 */
2902xmlXPathFunction
2903xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2904 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00002905 xmlXPathFunction ret;
2906
Owen Taylor3473f882001-02-23 17:55:21 +00002907 if (ctxt == NULL)
2908 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002909 if (name == NULL)
2910 return(NULL);
2911
Thomas Broyerba4ad322001-07-26 16:55:21 +00002912 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002913 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002914
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002915 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002916 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002917 if (ret != NULL)
2918 return(ret);
2919 }
2920
2921 if (ctxt->funcHash == NULL)
2922 return(NULL);
2923
William M. Brackad0e67c2004-12-01 14:35:10 +00002924 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
2925 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002926}
2927
2928/**
2929 * xmlXPathRegisteredFuncsCleanup:
2930 * @ctxt: the XPath context
2931 *
2932 * Cleanup the XPath context data associated to registered functions
2933 */
2934void
2935xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2936 if (ctxt == NULL)
2937 return;
2938
2939 xmlHashFree(ctxt->funcHash, NULL);
2940 ctxt->funcHash = NULL;
2941}
2942
2943/************************************************************************
2944 * *
William M. Brack08171912003-12-29 02:52:11 +00002945 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00002946 * *
2947 ************************************************************************/
2948
2949/**
2950 * xmlXPathRegisterVariable:
2951 * @ctxt: the XPath context
2952 * @name: the variable name
2953 * @value: the variable value or NULL
2954 *
2955 * Register a new variable value. If @value is NULL it unregisters
2956 * the variable
2957 *
2958 * Returns 0 in case of success, -1 in case of error
2959 */
2960int
2961xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2962 xmlXPathObjectPtr value) {
2963 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2964}
2965
2966/**
2967 * xmlXPathRegisterVariableNS:
2968 * @ctxt: the XPath context
2969 * @name: the variable name
2970 * @ns_uri: the variable namespace URI
2971 * @value: the variable value or NULL
2972 *
2973 * Register a new variable value. If @value is NULL it unregisters
2974 * the variable
2975 *
2976 * Returns 0 in case of success, -1 in case of error
2977 */
2978int
2979xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2980 const xmlChar *ns_uri,
2981 xmlXPathObjectPtr value) {
2982 if (ctxt == NULL)
2983 return(-1);
2984 if (name == NULL)
2985 return(-1);
2986
2987 if (ctxt->varHash == NULL)
2988 ctxt->varHash = xmlHashCreate(0);
2989 if (ctxt->varHash == NULL)
2990 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002991 if (value == NULL)
2992 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2993 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002994 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2995 (void *) value,
2996 (xmlHashDeallocator)xmlXPathFreeObject));
2997}
2998
2999/**
3000 * xmlXPathRegisterVariableLookup:
3001 * @ctxt: the XPath context
3002 * @f: the lookup function
3003 * @data: the lookup data
3004 *
3005 * register an external mechanism to do variable lookup
3006 */
3007void
3008xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
3009 xmlXPathVariableLookupFunc f, void *data) {
3010 if (ctxt == NULL)
3011 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00003012 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00003013 ctxt->varLookupData = data;
3014}
3015
3016/**
3017 * xmlXPathVariableLookup:
3018 * @ctxt: the XPath context
3019 * @name: the variable name
3020 *
3021 * Search in the Variable array of the context for the given
3022 * variable value.
3023 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003024 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003025 */
3026xmlXPathObjectPtr
3027xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3028 if (ctxt == NULL)
3029 return(NULL);
3030
3031 if (ctxt->varLookupFunc != NULL) {
3032 xmlXPathObjectPtr ret;
3033
3034 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3035 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00003036 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003037 }
3038 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3039}
3040
3041/**
3042 * xmlXPathVariableLookupNS:
3043 * @ctxt: the XPath context
3044 * @name: the variable name
3045 * @ns_uri: the variable namespace URI
3046 *
3047 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00003048 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00003049 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003050 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003051 */
3052xmlXPathObjectPtr
3053xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3054 const xmlChar *ns_uri) {
3055 if (ctxt == NULL)
3056 return(NULL);
3057
3058 if (ctxt->varLookupFunc != NULL) {
3059 xmlXPathObjectPtr ret;
3060
3061 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3062 (ctxt->varLookupData, name, ns_uri);
3063 if (ret != NULL) return(ret);
3064 }
3065
3066 if (ctxt->varHash == NULL)
3067 return(NULL);
3068 if (name == NULL)
3069 return(NULL);
3070
Daniel Veillard8c357d52001-07-03 23:43:33 +00003071 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3072 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00003073}
3074
3075/**
3076 * xmlXPathRegisteredVariablesCleanup:
3077 * @ctxt: the XPath context
3078 *
3079 * Cleanup the XPath context data associated to registered variables
3080 */
3081void
3082xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3083 if (ctxt == NULL)
3084 return;
3085
Daniel Veillard76d66f42001-05-16 21:05:17 +00003086 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00003087 ctxt->varHash = NULL;
3088}
3089
3090/**
3091 * xmlXPathRegisterNs:
3092 * @ctxt: the XPath context
3093 * @prefix: the namespace prefix
3094 * @ns_uri: the namespace name
3095 *
3096 * Register a new namespace. If @ns_uri is NULL it unregisters
3097 * the namespace
3098 *
3099 * Returns 0 in case of success, -1 in case of error
3100 */
3101int
3102xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3103 const xmlChar *ns_uri) {
3104 if (ctxt == NULL)
3105 return(-1);
3106 if (prefix == NULL)
3107 return(-1);
3108
3109 if (ctxt->nsHash == NULL)
3110 ctxt->nsHash = xmlHashCreate(10);
3111 if (ctxt->nsHash == NULL)
3112 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003113 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003114 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003115 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003116 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003117 (xmlHashDeallocator)xmlFree));
3118}
3119
3120/**
3121 * xmlXPathNsLookup:
3122 * @ctxt: the XPath context
3123 * @prefix: the namespace prefix value
3124 *
3125 * Search in the namespace declaration array of the context for the given
3126 * namespace name associated to the given prefix
3127 *
3128 * Returns the value or NULL if not found
3129 */
3130const xmlChar *
3131xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3132 if (ctxt == NULL)
3133 return(NULL);
3134 if (prefix == NULL)
3135 return(NULL);
3136
3137#ifdef XML_XML_NAMESPACE
3138 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3139 return(XML_XML_NAMESPACE);
3140#endif
3141
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003142 if (ctxt->namespaces != NULL) {
3143 int i;
3144
3145 for (i = 0;i < ctxt->nsNr;i++) {
3146 if ((ctxt->namespaces[i] != NULL) &&
3147 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3148 return(ctxt->namespaces[i]->href);
3149 }
3150 }
Owen Taylor3473f882001-02-23 17:55:21 +00003151
3152 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3153}
3154
3155/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003156 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003157 * @ctxt: the XPath context
3158 *
3159 * Cleanup the XPath context data associated to registered variables
3160 */
3161void
3162xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3163 if (ctxt == NULL)
3164 return;
3165
Daniel Veillard42766c02002-08-22 20:52:17 +00003166 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003167 ctxt->nsHash = NULL;
3168}
3169
3170/************************************************************************
3171 * *
3172 * Routines to handle Values *
3173 * *
3174 ************************************************************************/
3175
William M. Brack08171912003-12-29 02:52:11 +00003176/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003177
3178/**
3179 * xmlXPathNewFloat:
3180 * @val: the double value
3181 *
3182 * Create a new xmlXPathObjectPtr of type double and of value @val
3183 *
3184 * Returns the newly created object.
3185 */
3186xmlXPathObjectPtr
3187xmlXPathNewFloat(double val) {
3188 xmlXPathObjectPtr ret;
3189
3190 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3191 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003192 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003193 return(NULL);
3194 }
3195 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3196 ret->type = XPATH_NUMBER;
3197 ret->floatval = val;
3198 return(ret);
3199}
3200
3201/**
3202 * xmlXPathNewBoolean:
3203 * @val: the boolean value
3204 *
3205 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3206 *
3207 * Returns the newly created object.
3208 */
3209xmlXPathObjectPtr
3210xmlXPathNewBoolean(int val) {
3211 xmlXPathObjectPtr ret;
3212
3213 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3214 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003215 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003216 return(NULL);
3217 }
3218 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3219 ret->type = XPATH_BOOLEAN;
3220 ret->boolval = (val != 0);
3221 return(ret);
3222}
3223
3224/**
3225 * xmlXPathNewString:
3226 * @val: the xmlChar * value
3227 *
3228 * Create a new xmlXPathObjectPtr of type string and of value @val
3229 *
3230 * Returns the newly created object.
3231 */
3232xmlXPathObjectPtr
3233xmlXPathNewString(const xmlChar *val) {
3234 xmlXPathObjectPtr ret;
3235
3236 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3237 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003238 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003239 return(NULL);
3240 }
3241 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3242 ret->type = XPATH_STRING;
3243 if (val != NULL)
3244 ret->stringval = xmlStrdup(val);
3245 else
3246 ret->stringval = xmlStrdup((const xmlChar *)"");
3247 return(ret);
3248}
3249
3250/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003251 * xmlXPathWrapString:
3252 * @val: the xmlChar * value
3253 *
3254 * Wraps the @val string into an XPath object.
3255 *
3256 * Returns the newly created object.
3257 */
3258xmlXPathObjectPtr
3259xmlXPathWrapString (xmlChar *val) {
3260 xmlXPathObjectPtr ret;
3261
3262 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3263 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003264 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003265 return(NULL);
3266 }
3267 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3268 ret->type = XPATH_STRING;
3269 ret->stringval = val;
3270 return(ret);
3271}
3272
3273/**
Owen Taylor3473f882001-02-23 17:55:21 +00003274 * xmlXPathNewCString:
3275 * @val: the char * value
3276 *
3277 * Create a new xmlXPathObjectPtr of type string and of value @val
3278 *
3279 * Returns the newly created object.
3280 */
3281xmlXPathObjectPtr
3282xmlXPathNewCString(const char *val) {
3283 xmlXPathObjectPtr ret;
3284
3285 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3286 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003287 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003288 return(NULL);
3289 }
3290 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3291 ret->type = XPATH_STRING;
3292 ret->stringval = xmlStrdup(BAD_CAST val);
3293 return(ret);
3294}
3295
3296/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003297 * xmlXPathWrapCString:
3298 * @val: the char * value
3299 *
3300 * Wraps a string into an XPath object.
3301 *
3302 * Returns the newly created object.
3303 */
3304xmlXPathObjectPtr
3305xmlXPathWrapCString (char * val) {
3306 return(xmlXPathWrapString((xmlChar *)(val)));
3307}
3308
3309/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003310 * xmlXPathWrapExternal:
3311 * @val: the user data
3312 *
3313 * Wraps the @val data into an XPath object.
3314 *
3315 * Returns the newly created object.
3316 */
3317xmlXPathObjectPtr
3318xmlXPathWrapExternal (void *val) {
3319 xmlXPathObjectPtr ret;
3320
3321 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3322 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003323 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003324 return(NULL);
3325 }
3326 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3327 ret->type = XPATH_USERS;
3328 ret->user = val;
3329 return(ret);
3330}
3331
3332/**
Owen Taylor3473f882001-02-23 17:55:21 +00003333 * xmlXPathObjectCopy:
3334 * @val: the original object
3335 *
3336 * allocate a new copy of a given object
3337 *
3338 * Returns the newly created object.
3339 */
3340xmlXPathObjectPtr
3341xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3342 xmlXPathObjectPtr ret;
3343
3344 if (val == NULL)
3345 return(NULL);
3346
3347 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3348 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003349 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003350 return(NULL);
3351 }
3352 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3353 switch (val->type) {
3354 case XPATH_BOOLEAN:
3355 case XPATH_NUMBER:
3356 case XPATH_POINT:
3357 case XPATH_RANGE:
3358 break;
3359 case XPATH_STRING:
3360 ret->stringval = xmlStrdup(val->stringval);
3361 break;
3362 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00003363#if 0
3364/*
3365 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
3366 this previous handling is no longer correct, and can cause some serious
3367 problems (ref. bug 145547)
3368*/
Owen Taylor3473f882001-02-23 17:55:21 +00003369 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003370 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003371 xmlNodePtr cur, tmp;
3372 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003373
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003374 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003375 top = xmlNewDoc(NULL);
3376 top->name = (char *)
3377 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003378 ret->user = top;
3379 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003380 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003381 cur = val->nodesetval->nodeTab[0]->children;
3382 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003383 tmp = xmlDocCopyNode(cur, top, 1);
3384 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003385 cur = cur->next;
3386 }
3387 }
William M. Bracke9449c52004-07-11 14:41:20 +00003388
Daniel Veillard9adc0462003-03-24 18:39:54 +00003389 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003390 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003391 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003392 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003393 break;
William M. Bracke9449c52004-07-11 14:41:20 +00003394#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003395 case XPATH_NODESET:
3396 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003397 /* Do not deallocate the copied tree value */
3398 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003399 break;
3400 case XPATH_LOCATIONSET:
3401#ifdef LIBXML_XPTR_ENABLED
3402 {
3403 xmlLocationSetPtr loc = val->user;
3404 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3405 break;
3406 }
3407#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003408 case XPATH_USERS:
3409 ret->user = val->user;
3410 break;
3411 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003412 xmlGenericError(xmlGenericErrorContext,
3413 "xmlXPathObjectCopy: unsupported type %d\n",
3414 val->type);
3415 break;
3416 }
3417 return(ret);
3418}
3419
3420/**
3421 * xmlXPathFreeObject:
3422 * @obj: the object to free
3423 *
3424 * Free up an xmlXPathObjectPtr object.
3425 */
3426void
3427xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3428 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003429 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003430 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00003431#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003432 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003433 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003434 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003435 } else
3436#endif
3437 if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003438 xmlXPathFreeValueTree(obj->nodesetval);
3439 } else {
3440 if (obj->nodesetval != NULL)
3441 xmlXPathFreeNodeSet(obj->nodesetval);
3442 }
Owen Taylor3473f882001-02-23 17:55:21 +00003443#ifdef LIBXML_XPTR_ENABLED
3444 } else if (obj->type == XPATH_LOCATIONSET) {
3445 if (obj->user != NULL)
3446 xmlXPtrFreeLocationSet(obj->user);
3447#endif
3448 } else if (obj->type == XPATH_STRING) {
3449 if (obj->stringval != NULL)
3450 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003451 }
3452
Owen Taylor3473f882001-02-23 17:55:21 +00003453 xmlFree(obj);
3454}
3455
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003456
3457/************************************************************************
3458 * *
3459 * Type Casting Routines *
3460 * *
3461 ************************************************************************/
3462
3463/**
3464 * xmlXPathCastBooleanToString:
3465 * @val: a boolean
3466 *
3467 * Converts a boolean to its string value.
3468 *
3469 * Returns a newly allocated string.
3470 */
3471xmlChar *
3472xmlXPathCastBooleanToString (int val) {
3473 xmlChar *ret;
3474 if (val)
3475 ret = xmlStrdup((const xmlChar *) "true");
3476 else
3477 ret = xmlStrdup((const xmlChar *) "false");
3478 return(ret);
3479}
3480
3481/**
3482 * xmlXPathCastNumberToString:
3483 * @val: a number
3484 *
3485 * Converts a number to its string value.
3486 *
3487 * Returns a newly allocated string.
3488 */
3489xmlChar *
3490xmlXPathCastNumberToString (double val) {
3491 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003492 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003493 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003494 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003495 break;
3496 case -1:
3497 ret = xmlStrdup((const xmlChar *) "-Infinity");
3498 break;
3499 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003500 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003501 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003502 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3503 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003504 } else {
3505 /* could be improved */
3506 char buf[100];
3507 xmlXPathFormatNumber(val, buf, 100);
3508 ret = xmlStrdup((const xmlChar *) buf);
3509 }
3510 }
3511 return(ret);
3512}
3513
3514/**
3515 * xmlXPathCastNodeToString:
3516 * @node: a node
3517 *
3518 * Converts a node to its string value.
3519 *
3520 * Returns a newly allocated string.
3521 */
3522xmlChar *
3523xmlXPathCastNodeToString (xmlNodePtr node) {
3524 return(xmlNodeGetContent(node));
3525}
3526
3527/**
3528 * xmlXPathCastNodeSetToString:
3529 * @ns: a node-set
3530 *
3531 * Converts a node-set to its string value.
3532 *
3533 * Returns a newly allocated string.
3534 */
3535xmlChar *
3536xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3537 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3538 return(xmlStrdup((const xmlChar *) ""));
3539
3540 xmlXPathNodeSetSort(ns);
3541 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3542}
3543
3544/**
3545 * xmlXPathCastToString:
3546 * @val: an XPath object
3547 *
3548 * Converts an existing object to its string() equivalent
3549 *
3550 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003551 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003552 * string object).
3553 */
3554xmlChar *
3555xmlXPathCastToString(xmlXPathObjectPtr val) {
3556 xmlChar *ret = NULL;
3557
3558 if (val == NULL)
3559 return(xmlStrdup((const xmlChar *) ""));
3560 switch (val->type) {
3561 case XPATH_UNDEFINED:
3562#ifdef DEBUG_EXPR
3563 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3564#endif
3565 ret = xmlStrdup((const xmlChar *) "");
3566 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003567 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003568 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003569 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3570 break;
3571 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003572 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003573 case XPATH_BOOLEAN:
3574 ret = xmlXPathCastBooleanToString(val->boolval);
3575 break;
3576 case XPATH_NUMBER: {
3577 ret = xmlXPathCastNumberToString(val->floatval);
3578 break;
3579 }
3580 case XPATH_USERS:
3581 case XPATH_POINT:
3582 case XPATH_RANGE:
3583 case XPATH_LOCATIONSET:
3584 TODO
3585 ret = xmlStrdup((const xmlChar *) "");
3586 break;
3587 }
3588 return(ret);
3589}
3590
3591/**
3592 * xmlXPathConvertString:
3593 * @val: an XPath object
3594 *
3595 * Converts an existing object to its string() equivalent
3596 *
3597 * Returns the new object, the old one is freed (or the operation
3598 * is done directly on @val)
3599 */
3600xmlXPathObjectPtr
3601xmlXPathConvertString(xmlXPathObjectPtr val) {
3602 xmlChar *res = NULL;
3603
3604 if (val == NULL)
3605 return(xmlXPathNewCString(""));
3606
3607 switch (val->type) {
3608 case XPATH_UNDEFINED:
3609#ifdef DEBUG_EXPR
3610 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3611#endif
3612 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003613 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003614 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003615 res = xmlXPathCastNodeSetToString(val->nodesetval);
3616 break;
3617 case XPATH_STRING:
3618 return(val);
3619 case XPATH_BOOLEAN:
3620 res = xmlXPathCastBooleanToString(val->boolval);
3621 break;
3622 case XPATH_NUMBER:
3623 res = xmlXPathCastNumberToString(val->floatval);
3624 break;
3625 case XPATH_USERS:
3626 case XPATH_POINT:
3627 case XPATH_RANGE:
3628 case XPATH_LOCATIONSET:
3629 TODO;
3630 break;
3631 }
3632 xmlXPathFreeObject(val);
3633 if (res == NULL)
3634 return(xmlXPathNewCString(""));
3635 return(xmlXPathWrapString(res));
3636}
3637
3638/**
3639 * xmlXPathCastBooleanToNumber:
3640 * @val: a boolean
3641 *
3642 * Converts a boolean to its number value
3643 *
3644 * Returns the number value
3645 */
3646double
3647xmlXPathCastBooleanToNumber(int val) {
3648 if (val)
3649 return(1.0);
3650 return(0.0);
3651}
3652
3653/**
3654 * xmlXPathCastStringToNumber:
3655 * @val: a string
3656 *
3657 * Converts a string to its number value
3658 *
3659 * Returns the number value
3660 */
3661double
3662xmlXPathCastStringToNumber(const xmlChar * val) {
3663 return(xmlXPathStringEvalNumber(val));
3664}
3665
3666/**
3667 * xmlXPathCastNodeToNumber:
3668 * @node: a node
3669 *
3670 * Converts a node to its number value
3671 *
3672 * Returns the number value
3673 */
3674double
3675xmlXPathCastNodeToNumber (xmlNodePtr node) {
3676 xmlChar *strval;
3677 double ret;
3678
3679 if (node == NULL)
3680 return(xmlXPathNAN);
3681 strval = xmlXPathCastNodeToString(node);
3682 if (strval == NULL)
3683 return(xmlXPathNAN);
3684 ret = xmlXPathCastStringToNumber(strval);
3685 xmlFree(strval);
3686
3687 return(ret);
3688}
3689
3690/**
3691 * xmlXPathCastNodeSetToNumber:
3692 * @ns: a node-set
3693 *
3694 * Converts a node-set to its number value
3695 *
3696 * Returns the number value
3697 */
3698double
3699xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3700 xmlChar *str;
3701 double ret;
3702
3703 if (ns == NULL)
3704 return(xmlXPathNAN);
3705 str = xmlXPathCastNodeSetToString(ns);
3706 ret = xmlXPathCastStringToNumber(str);
3707 xmlFree(str);
3708 return(ret);
3709}
3710
3711/**
3712 * xmlXPathCastToNumber:
3713 * @val: an XPath object
3714 *
3715 * Converts an XPath object to its number value
3716 *
3717 * Returns the number value
3718 */
3719double
3720xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3721 double ret = 0.0;
3722
3723 if (val == NULL)
3724 return(xmlXPathNAN);
3725 switch (val->type) {
3726 case XPATH_UNDEFINED:
3727#ifdef DEGUB_EXPR
3728 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3729#endif
3730 ret = xmlXPathNAN;
3731 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003732 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003733 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003734 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3735 break;
3736 case XPATH_STRING:
3737 ret = xmlXPathCastStringToNumber(val->stringval);
3738 break;
3739 case XPATH_NUMBER:
3740 ret = val->floatval;
3741 break;
3742 case XPATH_BOOLEAN:
3743 ret = xmlXPathCastBooleanToNumber(val->boolval);
3744 break;
3745 case XPATH_USERS:
3746 case XPATH_POINT:
3747 case XPATH_RANGE:
3748 case XPATH_LOCATIONSET:
3749 TODO;
3750 ret = xmlXPathNAN;
3751 break;
3752 }
3753 return(ret);
3754}
3755
3756/**
3757 * xmlXPathConvertNumber:
3758 * @val: an XPath object
3759 *
3760 * Converts an existing object to its number() equivalent
3761 *
3762 * Returns the new object, the old one is freed (or the operation
3763 * is done directly on @val)
3764 */
3765xmlXPathObjectPtr
3766xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3767 xmlXPathObjectPtr ret;
3768
3769 if (val == NULL)
3770 return(xmlXPathNewFloat(0.0));
3771 if (val->type == XPATH_NUMBER)
3772 return(val);
3773 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3774 xmlXPathFreeObject(val);
3775 return(ret);
3776}
3777
3778/**
3779 * xmlXPathCastNumberToBoolean:
3780 * @val: a number
3781 *
3782 * Converts a number to its boolean value
3783 *
3784 * Returns the boolean value
3785 */
3786int
3787xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003788 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003789 return(0);
3790 return(1);
3791}
3792
3793/**
3794 * xmlXPathCastStringToBoolean:
3795 * @val: a string
3796 *
3797 * Converts a string to its boolean value
3798 *
3799 * Returns the boolean value
3800 */
3801int
3802xmlXPathCastStringToBoolean (const xmlChar *val) {
3803 if ((val == NULL) || (xmlStrlen(val) == 0))
3804 return(0);
3805 return(1);
3806}
3807
3808/**
3809 * xmlXPathCastNodeSetToBoolean:
3810 * @ns: a node-set
3811 *
3812 * Converts a node-set to its boolean value
3813 *
3814 * Returns the boolean value
3815 */
3816int
3817xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3818 if ((ns == NULL) || (ns->nodeNr == 0))
3819 return(0);
3820 return(1);
3821}
3822
3823/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003824 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003825 * @val: an XPath object
3826 *
3827 * Converts an XPath object to its boolean value
3828 *
3829 * Returns the boolean value
3830 */
3831int
3832xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3833 int ret = 0;
3834
3835 if (val == NULL)
3836 return(0);
3837 switch (val->type) {
3838 case XPATH_UNDEFINED:
3839#ifdef DEBUG_EXPR
3840 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3841#endif
3842 ret = 0;
3843 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003844 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003845 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003846 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3847 break;
3848 case XPATH_STRING:
3849 ret = xmlXPathCastStringToBoolean(val->stringval);
3850 break;
3851 case XPATH_NUMBER:
3852 ret = xmlXPathCastNumberToBoolean(val->floatval);
3853 break;
3854 case XPATH_BOOLEAN:
3855 ret = val->boolval;
3856 break;
3857 case XPATH_USERS:
3858 case XPATH_POINT:
3859 case XPATH_RANGE:
3860 case XPATH_LOCATIONSET:
3861 TODO;
3862 ret = 0;
3863 break;
3864 }
3865 return(ret);
3866}
3867
3868
3869/**
3870 * xmlXPathConvertBoolean:
3871 * @val: an XPath object
3872 *
3873 * Converts an existing object to its boolean() equivalent
3874 *
3875 * Returns the new object, the old one is freed (or the operation
3876 * is done directly on @val)
3877 */
3878xmlXPathObjectPtr
3879xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3880 xmlXPathObjectPtr ret;
3881
3882 if (val == NULL)
3883 return(xmlXPathNewBoolean(0));
3884 if (val->type == XPATH_BOOLEAN)
3885 return(val);
3886 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3887 xmlXPathFreeObject(val);
3888 return(ret);
3889}
3890
Owen Taylor3473f882001-02-23 17:55:21 +00003891/************************************************************************
3892 * *
3893 * Routines to handle XPath contexts *
3894 * *
3895 ************************************************************************/
3896
3897/**
3898 * xmlXPathNewContext:
3899 * @doc: the XML document
3900 *
3901 * Create a new xmlXPathContext
3902 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003903 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003904 */
3905xmlXPathContextPtr
3906xmlXPathNewContext(xmlDocPtr doc) {
3907 xmlXPathContextPtr ret;
3908
3909 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3910 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003911 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003912 return(NULL);
3913 }
3914 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3915 ret->doc = doc;
3916 ret->node = NULL;
3917
3918 ret->varHash = NULL;
3919
3920 ret->nb_types = 0;
3921 ret->max_types = 0;
3922 ret->types = NULL;
3923
3924 ret->funcHash = xmlHashCreate(0);
3925
3926 ret->nb_axis = 0;
3927 ret->max_axis = 0;
3928 ret->axis = NULL;
3929
3930 ret->nsHash = NULL;
3931 ret->user = NULL;
3932
3933 ret->contextSize = -1;
3934 ret->proximityPosition = -1;
3935
3936 xmlXPathRegisterAllFunctions(ret);
3937
3938 return(ret);
3939}
3940
3941/**
3942 * xmlXPathFreeContext:
3943 * @ctxt: the context to free
3944 *
3945 * Free up an xmlXPathContext
3946 */
3947void
3948xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00003949 if (ctxt == NULL) return;
3950
Owen Taylor3473f882001-02-23 17:55:21 +00003951 xmlXPathRegisteredNsCleanup(ctxt);
3952 xmlXPathRegisteredFuncsCleanup(ctxt);
3953 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00003954 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00003955 xmlFree(ctxt);
3956}
3957
3958/************************************************************************
3959 * *
3960 * Routines to handle XPath parser contexts *
3961 * *
3962 ************************************************************************/
3963
3964#define CHECK_CTXT(ctxt) \
3965 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00003966 __xmlRaiseError(NULL, NULL, NULL, \
3967 NULL, NULL, XML_FROM_XPATH, \
3968 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
3969 __FILE__, __LINE__, \
3970 NULL, NULL, NULL, 0, 0, \
3971 "NULL context pointer\n"); \
3972 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00003973 } \
3974
3975
3976#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00003977 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
3978 (ctxt->doc->children == NULL)) { \
3979 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00003980 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00003981 }
Owen Taylor3473f882001-02-23 17:55:21 +00003982
3983
3984/**
3985 * xmlXPathNewParserContext:
3986 * @str: the XPath expression
3987 * @ctxt: the XPath context
3988 *
3989 * Create a new xmlXPathParserContext
3990 *
3991 * Returns the xmlXPathParserContext just allocated.
3992 */
3993xmlXPathParserContextPtr
3994xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3995 xmlXPathParserContextPtr ret;
3996
3997 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3998 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003999 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004000 return(NULL);
4001 }
4002 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4003 ret->cur = ret->base = str;
4004 ret->context = ctxt;
4005
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004006 ret->comp = xmlXPathNewCompExpr();
4007 if (ret->comp == NULL) {
4008 xmlFree(ret->valueTab);
4009 xmlFree(ret);
4010 return(NULL);
4011 }
Daniel Veillard4773df22004-01-23 13:15:13 +00004012 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4013 ret->comp->dict = ctxt->dict;
4014 xmlDictReference(ret->comp->dict);
4015 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004016
4017 return(ret);
4018}
4019
4020/**
4021 * xmlXPathCompParserContext:
4022 * @comp: the XPath compiled expression
4023 * @ctxt: the XPath context
4024 *
4025 * Create a new xmlXPathParserContext when processing a compiled expression
4026 *
4027 * Returns the xmlXPathParserContext just allocated.
4028 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004029static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004030xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4031 xmlXPathParserContextPtr ret;
4032
4033 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4034 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004035 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004036 return(NULL);
4037 }
4038 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4039
Owen Taylor3473f882001-02-23 17:55:21 +00004040 /* Allocate the value stack */
4041 ret->valueTab = (xmlXPathObjectPtr *)
4042 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004043 if (ret->valueTab == NULL) {
4044 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004045 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004046 return(NULL);
4047 }
Owen Taylor3473f882001-02-23 17:55:21 +00004048 ret->valueNr = 0;
4049 ret->valueMax = 10;
4050 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004051
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004052 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004053 ret->comp = comp;
4054
Owen Taylor3473f882001-02-23 17:55:21 +00004055 return(ret);
4056}
4057
4058/**
4059 * xmlXPathFreeParserContext:
4060 * @ctxt: the context to free
4061 *
4062 * Free up an xmlXPathParserContext
4063 */
4064void
4065xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
4066 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004067 xmlFree(ctxt->valueTab);
4068 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00004069 if (ctxt->comp != NULL) {
4070#ifdef XPATH_STREAMING
4071 if (ctxt->comp->stream != NULL) {
4072 xmlFreePatternList(ctxt->comp->stream);
4073 ctxt->comp->stream = NULL;
4074 }
4075#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004076 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00004077 }
Owen Taylor3473f882001-02-23 17:55:21 +00004078 xmlFree(ctxt);
4079}
4080
4081/************************************************************************
4082 * *
4083 * The implicit core function library *
4084 * *
4085 ************************************************************************/
4086
Owen Taylor3473f882001-02-23 17:55:21 +00004087/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004088 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00004089 * @node: a node pointer
4090 *
4091 * Function computing the beginning of the string value of the node,
4092 * used to speed up comparisons
4093 *
4094 * Returns an int usable as a hash
4095 */
4096static unsigned int
4097xmlXPathNodeValHash(xmlNodePtr node) {
4098 int len = 2;
4099 const xmlChar * string = NULL;
4100 xmlNodePtr tmp = NULL;
4101 unsigned int ret = 0;
4102
4103 if (node == NULL)
4104 return(0);
4105
Daniel Veillard9adc0462003-03-24 18:39:54 +00004106 if (node->type == XML_DOCUMENT_NODE) {
4107 tmp = xmlDocGetRootElement((xmlDocPtr) node);
4108 if (tmp == NULL)
4109 node = node->children;
4110 else
4111 node = tmp;
4112
4113 if (node == NULL)
4114 return(0);
4115 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004116
4117 switch (node->type) {
4118 case XML_COMMENT_NODE:
4119 case XML_PI_NODE:
4120 case XML_CDATA_SECTION_NODE:
4121 case XML_TEXT_NODE:
4122 string = node->content;
4123 if (string == NULL)
4124 return(0);
4125 if (string[0] == 0)
4126 return(0);
4127 return(((unsigned int) string[0]) +
4128 (((unsigned int) string[1]) << 8));
4129 case XML_NAMESPACE_DECL:
4130 string = ((xmlNsPtr)node)->href;
4131 if (string == NULL)
4132 return(0);
4133 if (string[0] == 0)
4134 return(0);
4135 return(((unsigned int) string[0]) +
4136 (((unsigned int) string[1]) << 8));
4137 case XML_ATTRIBUTE_NODE:
4138 tmp = ((xmlAttrPtr) node)->children;
4139 break;
4140 case XML_ELEMENT_NODE:
4141 tmp = node->children;
4142 break;
4143 default:
4144 return(0);
4145 }
4146 while (tmp != NULL) {
4147 switch (tmp->type) {
4148 case XML_COMMENT_NODE:
4149 case XML_PI_NODE:
4150 case XML_CDATA_SECTION_NODE:
4151 case XML_TEXT_NODE:
4152 string = tmp->content;
4153 break;
4154 case XML_NAMESPACE_DECL:
4155 string = ((xmlNsPtr)tmp)->href;
4156 break;
4157 default:
4158 break;
4159 }
4160 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004161 if (len == 1) {
4162 return(ret + (((unsigned int) string[0]) << 8));
4163 }
4164 if (string[1] == 0) {
4165 len = 1;
4166 ret = (unsigned int) string[0];
4167 } else {
4168 return(((unsigned int) string[0]) +
4169 (((unsigned int) string[1]) << 8));
4170 }
4171 }
4172 /*
4173 * Skip to next node
4174 */
4175 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4176 if (tmp->children->type != XML_ENTITY_DECL) {
4177 tmp = tmp->children;
4178 continue;
4179 }
4180 }
4181 if (tmp == node)
4182 break;
4183
4184 if (tmp->next != NULL) {
4185 tmp = tmp->next;
4186 continue;
4187 }
4188
4189 do {
4190 tmp = tmp->parent;
4191 if (tmp == NULL)
4192 break;
4193 if (tmp == node) {
4194 tmp = NULL;
4195 break;
4196 }
4197 if (tmp->next != NULL) {
4198 tmp = tmp->next;
4199 break;
4200 }
4201 } while (tmp != NULL);
4202 }
4203 return(ret);
4204}
4205
4206/**
4207 * xmlXPathStringHash:
4208 * @string: a string
4209 *
4210 * Function computing the beginning of the string value of the node,
4211 * used to speed up comparisons
4212 *
4213 * Returns an int usable as a hash
4214 */
4215static unsigned int
4216xmlXPathStringHash(const xmlChar * string) {
4217 if (string == NULL)
4218 return((unsigned int) 0);
4219 if (string[0] == 0)
4220 return(0);
4221 return(((unsigned int) string[0]) +
4222 (((unsigned int) string[1]) << 8));
4223}
4224
4225/**
Owen Taylor3473f882001-02-23 17:55:21 +00004226 * xmlXPathCompareNodeSetFloat:
4227 * @ctxt: the XPath Parser context
4228 * @inf: less than (1) or greater than (0)
4229 * @strict: is the comparison strict
4230 * @arg: the node set
4231 * @f: the value
4232 *
4233 * Implement the compare operation between a nodeset and a number
4234 * @ns < @val (1, 1, ...
4235 * @ns <= @val (1, 0, ...
4236 * @ns > @val (0, 1, ...
4237 * @ns >= @val (0, 0, ...
4238 *
4239 * If one object to be compared is a node-set and the other is a number,
4240 * then the comparison will be true if and only if there is a node in the
4241 * node-set such that the result of performing the comparison on the number
4242 * to be compared and on the result of converting the string-value of that
4243 * node to a number using the number function is true.
4244 *
4245 * Returns 0 or 1 depending on the results of the test.
4246 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004247static int
Owen Taylor3473f882001-02-23 17:55:21 +00004248xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4249 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4250 int i, ret = 0;
4251 xmlNodeSetPtr ns;
4252 xmlChar *str2;
4253
4254 if ((f == NULL) || (arg == NULL) ||
4255 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4256 xmlXPathFreeObject(arg);
4257 xmlXPathFreeObject(f);
4258 return(0);
4259 }
4260 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004261 if (ns != NULL) {
4262 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004263 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004264 if (str2 != NULL) {
4265 valuePush(ctxt,
4266 xmlXPathNewString(str2));
4267 xmlFree(str2);
4268 xmlXPathNumberFunction(ctxt, 1);
4269 valuePush(ctxt, xmlXPathObjectCopy(f));
4270 ret = xmlXPathCompareValues(ctxt, inf, strict);
4271 if (ret)
4272 break;
4273 }
4274 }
Owen Taylor3473f882001-02-23 17:55:21 +00004275 }
4276 xmlXPathFreeObject(arg);
4277 xmlXPathFreeObject(f);
4278 return(ret);
4279}
4280
4281/**
4282 * xmlXPathCompareNodeSetString:
4283 * @ctxt: the XPath Parser context
4284 * @inf: less than (1) or greater than (0)
4285 * @strict: is the comparison strict
4286 * @arg: the node set
4287 * @s: the value
4288 *
4289 * Implement the compare operation between a nodeset and a string
4290 * @ns < @val (1, 1, ...
4291 * @ns <= @val (1, 0, ...
4292 * @ns > @val (0, 1, ...
4293 * @ns >= @val (0, 0, ...
4294 *
4295 * If one object to be compared is a node-set and the other is a string,
4296 * then the comparison will be true if and only if there is a node in
4297 * the node-set such that the result of performing the comparison on the
4298 * string-value of the node and the other string is true.
4299 *
4300 * Returns 0 or 1 depending on the results of the test.
4301 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004302static int
Owen Taylor3473f882001-02-23 17:55:21 +00004303xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4304 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4305 int i, ret = 0;
4306 xmlNodeSetPtr ns;
4307 xmlChar *str2;
4308
4309 if ((s == NULL) || (arg == NULL) ||
4310 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4311 xmlXPathFreeObject(arg);
4312 xmlXPathFreeObject(s);
4313 return(0);
4314 }
4315 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004316 if (ns != NULL) {
4317 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004318 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004319 if (str2 != NULL) {
4320 valuePush(ctxt,
4321 xmlXPathNewString(str2));
4322 xmlFree(str2);
4323 valuePush(ctxt, xmlXPathObjectCopy(s));
4324 ret = xmlXPathCompareValues(ctxt, inf, strict);
4325 if (ret)
4326 break;
4327 }
4328 }
Owen Taylor3473f882001-02-23 17:55:21 +00004329 }
4330 xmlXPathFreeObject(arg);
4331 xmlXPathFreeObject(s);
4332 return(ret);
4333}
4334
4335/**
4336 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004337 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004338 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004339 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004340 * @arg2: the second node set object
4341 *
4342 * Implement the compare operation on nodesets:
4343 *
4344 * If both objects to be compared are node-sets, then the comparison
4345 * will be true if and only if there is a node in the first node-set
4346 * and a node in the second node-set such that the result of performing
4347 * the comparison on the string-values of the two nodes is true.
4348 * ....
4349 * When neither object to be compared is a node-set and the operator
4350 * is <=, <, >= or >, then the objects are compared by converting both
4351 * objects to numbers and comparing the numbers according to IEEE 754.
4352 * ....
4353 * The number function converts its argument to a number as follows:
4354 * - a string that consists of optional whitespace followed by an
4355 * optional minus sign followed by a Number followed by whitespace
4356 * is converted to the IEEE 754 number that is nearest (according
4357 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4358 * represented by the string; any other string is converted to NaN
4359 *
4360 * Conclusion all nodes need to be converted first to their string value
4361 * and then the comparison must be done when possible
4362 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004363static int
4364xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004365 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4366 int i, j, init = 0;
4367 double val1;
4368 double *values2;
4369 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004370 xmlNodeSetPtr ns1;
4371 xmlNodeSetPtr ns2;
4372
4373 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004374 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4375 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004376 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004377 }
Owen Taylor3473f882001-02-23 17:55:21 +00004378 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004379 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4380 xmlXPathFreeObject(arg1);
4381 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004382 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004383 }
Owen Taylor3473f882001-02-23 17:55:21 +00004384
4385 ns1 = arg1->nodesetval;
4386 ns2 = arg2->nodesetval;
4387
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004388 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004389 xmlXPathFreeObject(arg1);
4390 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004391 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004392 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004393 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004394 xmlXPathFreeObject(arg1);
4395 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004396 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004397 }
Owen Taylor3473f882001-02-23 17:55:21 +00004398
4399 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4400 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004401 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004402 xmlXPathFreeObject(arg1);
4403 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004404 return(0);
4405 }
4406 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004407 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004408 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004409 continue;
4410 for (j = 0;j < ns2->nodeNr;j++) {
4411 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004412 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004413 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004414 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004415 continue;
4416 if (inf && strict)
4417 ret = (val1 < values2[j]);
4418 else if (inf && !strict)
4419 ret = (val1 <= values2[j]);
4420 else if (!inf && strict)
4421 ret = (val1 > values2[j]);
4422 else if (!inf && !strict)
4423 ret = (val1 >= values2[j]);
4424 if (ret)
4425 break;
4426 }
4427 if (ret)
4428 break;
4429 init = 1;
4430 }
4431 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004432 xmlXPathFreeObject(arg1);
4433 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004434 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004435}
4436
4437/**
4438 * xmlXPathCompareNodeSetValue:
4439 * @ctxt: the XPath Parser context
4440 * @inf: less than (1) or greater than (0)
4441 * @strict: is the comparison strict
4442 * @arg: the node set
4443 * @val: the value
4444 *
4445 * Implement the compare operation between a nodeset and a value
4446 * @ns < @val (1, 1, ...
4447 * @ns <= @val (1, 0, ...
4448 * @ns > @val (0, 1, ...
4449 * @ns >= @val (0, 0, ...
4450 *
4451 * If one object to be compared is a node-set and the other is a boolean,
4452 * then the comparison will be true if and only if the result of performing
4453 * the comparison on the boolean and on the result of converting
4454 * the node-set to a boolean using the boolean function is true.
4455 *
4456 * Returns 0 or 1 depending on the results of the test.
4457 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004458static int
Owen Taylor3473f882001-02-23 17:55:21 +00004459xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4460 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4461 if ((val == NULL) || (arg == NULL) ||
4462 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4463 return(0);
4464
4465 switch(val->type) {
4466 case XPATH_NUMBER:
4467 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4468 case XPATH_NODESET:
4469 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004470 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004471 case XPATH_STRING:
4472 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4473 case XPATH_BOOLEAN:
4474 valuePush(ctxt, arg);
4475 xmlXPathBooleanFunction(ctxt, 1);
4476 valuePush(ctxt, val);
4477 return(xmlXPathCompareValues(ctxt, inf, strict));
4478 default:
4479 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004480 }
4481 return(0);
4482}
4483
4484/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004485 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004486 * @arg: the nodeset object argument
4487 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004488 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004489 *
4490 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4491 * If one object to be compared is a node-set and the other is a string,
4492 * then the comparison will be true if and only if there is a node in
4493 * the node-set such that the result of performing the comparison on the
4494 * string-value of the node and the other string is true.
4495 *
4496 * Returns 0 or 1 depending on the results of the test.
4497 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004498static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004499xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004500{
Owen Taylor3473f882001-02-23 17:55:21 +00004501 int i;
4502 xmlNodeSetPtr ns;
4503 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004504 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004505
4506 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004507 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4508 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004509 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004510 /*
4511 * A NULL nodeset compared with a string is always false
4512 * (since there is no node equal, and no node not equal)
4513 */
4514 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004515 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004516 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004517 for (i = 0; i < ns->nodeNr; i++) {
4518 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4519 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4520 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4521 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004522 if (neq)
4523 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004524 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004525 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4526 if (neq)
4527 continue;
4528 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004529 } else if (neq) {
4530 if (str2 != NULL)
4531 xmlFree(str2);
4532 return (1);
4533 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004534 if (str2 != NULL)
4535 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004536 } else if (neq)
4537 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004538 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004539 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004540}
4541
4542/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004543 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004544 * @arg: the nodeset object argument
4545 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004546 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004547 *
4548 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4549 * If one object to be compared is a node-set and the other is a number,
4550 * then the comparison will be true if and only if there is a node in
4551 * the node-set such that the result of performing the comparison on the
4552 * number to be compared and on the result of converting the string-value
4553 * of that node to a number using the number function is true.
4554 *
4555 * Returns 0 or 1 depending on the results of the test.
4556 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004557static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004558xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4559 xmlXPathObjectPtr arg, double f, int neq) {
4560 int i, ret=0;
4561 xmlNodeSetPtr ns;
4562 xmlChar *str2;
4563 xmlXPathObjectPtr val;
4564 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004565
4566 if ((arg == NULL) ||
4567 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4568 return(0);
4569
William M. Brack0c022ad2002-07-12 00:56:01 +00004570 ns = arg->nodesetval;
4571 if (ns != NULL) {
4572 for (i=0;i<ns->nodeNr;i++) {
4573 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4574 if (str2 != NULL) {
4575 valuePush(ctxt, xmlXPathNewString(str2));
4576 xmlFree(str2);
4577 xmlXPathNumberFunction(ctxt, 1);
4578 val = valuePop(ctxt);
4579 v = val->floatval;
4580 xmlXPathFreeObject(val);
4581 if (!xmlXPathIsNaN(v)) {
4582 if ((!neq) && (v==f)) {
4583 ret = 1;
4584 break;
4585 } else if ((neq) && (v!=f)) {
4586 ret = 1;
4587 break;
4588 }
4589 }
4590 }
4591 }
4592 }
4593
4594 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004595}
4596
4597
4598/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004599 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004600 * @arg1: first nodeset object argument
4601 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004602 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004603 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004604 * Implement the equal / not equal operation on XPath nodesets:
4605 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004606 * If both objects to be compared are node-sets, then the comparison
4607 * will be true if and only if there is a node in the first node-set and
4608 * a node in the second node-set such that the result of performing the
4609 * comparison on the string-values of the two nodes is true.
4610 *
4611 * (needless to say, this is a costly operation)
4612 *
4613 * Returns 0 or 1 depending on the results of the test.
4614 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004615static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004616xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004617 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004618 unsigned int *hashs1;
4619 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004620 xmlChar **values1;
4621 xmlChar **values2;
4622 int ret = 0;
4623 xmlNodeSetPtr ns1;
4624 xmlNodeSetPtr ns2;
4625
4626 if ((arg1 == NULL) ||
4627 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4628 return(0);
4629 if ((arg2 == NULL) ||
4630 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4631 return(0);
4632
4633 ns1 = arg1->nodesetval;
4634 ns2 = arg2->nodesetval;
4635
Daniel Veillard911f49a2001-04-07 15:39:35 +00004636 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004637 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004638 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004639 return(0);
4640
4641 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004642 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004643 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004644 if (neq == 0)
4645 for (i = 0;i < ns1->nodeNr;i++)
4646 for (j = 0;j < ns2->nodeNr;j++)
4647 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4648 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004649
4650 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004651 if (values1 == NULL) {
4652 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004653 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004654 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004655 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4656 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004657 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004658 xmlFree(values1);
4659 return(0);
4660 }
Owen Taylor3473f882001-02-23 17:55:21 +00004661 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4662 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4663 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004664 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004665 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004666 xmlFree(values1);
4667 return(0);
4668 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004669 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4670 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004671 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004672 xmlFree(hashs1);
4673 xmlFree(values1);
4674 xmlFree(values2);
4675 return(0);
4676 }
Owen Taylor3473f882001-02-23 17:55:21 +00004677 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4678 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004679 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004680 for (j = 0;j < ns2->nodeNr;j++) {
4681 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004682 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004683 if (hashs1[i] != hashs2[j]) {
4684 if (neq) {
4685 ret = 1;
4686 break;
4687 }
4688 }
4689 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004690 if (values1[i] == NULL)
4691 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4692 if (values2[j] == NULL)
4693 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004694 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004695 if (ret)
4696 break;
4697 }
Owen Taylor3473f882001-02-23 17:55:21 +00004698 }
4699 if (ret)
4700 break;
4701 }
4702 for (i = 0;i < ns1->nodeNr;i++)
4703 if (values1[i] != NULL)
4704 xmlFree(values1[i]);
4705 for (j = 0;j < ns2->nodeNr;j++)
4706 if (values2[j] != NULL)
4707 xmlFree(values2[j]);
4708 xmlFree(values1);
4709 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004710 xmlFree(hashs1);
4711 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004712 return(ret);
4713}
4714
William M. Brack0c022ad2002-07-12 00:56:01 +00004715static int
4716xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4717 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004718 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004719 /*
4720 *At this point we are assured neither arg1 nor arg2
4721 *is a nodeset, so we can just pick the appropriate routine.
4722 */
Owen Taylor3473f882001-02-23 17:55:21 +00004723 switch (arg1->type) {
4724 case XPATH_UNDEFINED:
4725#ifdef DEBUG_EXPR
4726 xmlGenericError(xmlGenericErrorContext,
4727 "Equal: undefined\n");
4728#endif
4729 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004730 case XPATH_BOOLEAN:
4731 switch (arg2->type) {
4732 case XPATH_UNDEFINED:
4733#ifdef DEBUG_EXPR
4734 xmlGenericError(xmlGenericErrorContext,
4735 "Equal: undefined\n");
4736#endif
4737 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004738 case XPATH_BOOLEAN:
4739#ifdef DEBUG_EXPR
4740 xmlGenericError(xmlGenericErrorContext,
4741 "Equal: %d boolean %d \n",
4742 arg1->boolval, arg2->boolval);
4743#endif
4744 ret = (arg1->boolval == arg2->boolval);
4745 break;
4746 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004747 ret = (arg1->boolval ==
4748 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004749 break;
4750 case XPATH_STRING:
4751 if ((arg2->stringval == NULL) ||
4752 (arg2->stringval[0] == 0)) ret = 0;
4753 else
4754 ret = 1;
4755 ret = (arg1->boolval == ret);
4756 break;
4757 case XPATH_USERS:
4758 case XPATH_POINT:
4759 case XPATH_RANGE:
4760 case XPATH_LOCATIONSET:
4761 TODO
4762 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004763 case XPATH_NODESET:
4764 case XPATH_XSLT_TREE:
4765 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004766 }
4767 break;
4768 case XPATH_NUMBER:
4769 switch (arg2->type) {
4770 case XPATH_UNDEFINED:
4771#ifdef DEBUG_EXPR
4772 xmlGenericError(xmlGenericErrorContext,
4773 "Equal: undefined\n");
4774#endif
4775 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004776 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004777 ret = (arg2->boolval==
4778 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004779 break;
4780 case XPATH_STRING:
4781 valuePush(ctxt, arg2);
4782 xmlXPathNumberFunction(ctxt, 1);
4783 arg2 = valuePop(ctxt);
4784 /* no break on purpose */
4785 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004786 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004787 if (xmlXPathIsNaN(arg1->floatval) ||
4788 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004789 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004790 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4791 if (xmlXPathIsInf(arg2->floatval) == 1)
4792 ret = 1;
4793 else
4794 ret = 0;
4795 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4796 if (xmlXPathIsInf(arg2->floatval) == -1)
4797 ret = 1;
4798 else
4799 ret = 0;
4800 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4801 if (xmlXPathIsInf(arg1->floatval) == 1)
4802 ret = 1;
4803 else
4804 ret = 0;
4805 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4806 if (xmlXPathIsInf(arg1->floatval) == -1)
4807 ret = 1;
4808 else
4809 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004810 } else {
4811 ret = (arg1->floatval == arg2->floatval);
4812 }
Owen Taylor3473f882001-02-23 17:55:21 +00004813 break;
4814 case XPATH_USERS:
4815 case XPATH_POINT:
4816 case XPATH_RANGE:
4817 case XPATH_LOCATIONSET:
4818 TODO
4819 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004820 case XPATH_NODESET:
4821 case XPATH_XSLT_TREE:
4822 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004823 }
4824 break;
4825 case XPATH_STRING:
4826 switch (arg2->type) {
4827 case XPATH_UNDEFINED:
4828#ifdef DEBUG_EXPR
4829 xmlGenericError(xmlGenericErrorContext,
4830 "Equal: undefined\n");
4831#endif
4832 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004833 case XPATH_BOOLEAN:
4834 if ((arg1->stringval == NULL) ||
4835 (arg1->stringval[0] == 0)) ret = 0;
4836 else
4837 ret = 1;
4838 ret = (arg2->boolval == ret);
4839 break;
4840 case XPATH_STRING:
4841 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4842 break;
4843 case XPATH_NUMBER:
4844 valuePush(ctxt, arg1);
4845 xmlXPathNumberFunction(ctxt, 1);
4846 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004847 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004848 if (xmlXPathIsNaN(arg1->floatval) ||
4849 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004850 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004851 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4852 if (xmlXPathIsInf(arg2->floatval) == 1)
4853 ret = 1;
4854 else
4855 ret = 0;
4856 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4857 if (xmlXPathIsInf(arg2->floatval) == -1)
4858 ret = 1;
4859 else
4860 ret = 0;
4861 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4862 if (xmlXPathIsInf(arg1->floatval) == 1)
4863 ret = 1;
4864 else
4865 ret = 0;
4866 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4867 if (xmlXPathIsInf(arg1->floatval) == -1)
4868 ret = 1;
4869 else
4870 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004871 } else {
4872 ret = (arg1->floatval == arg2->floatval);
4873 }
Owen Taylor3473f882001-02-23 17:55:21 +00004874 break;
4875 case XPATH_USERS:
4876 case XPATH_POINT:
4877 case XPATH_RANGE:
4878 case XPATH_LOCATIONSET:
4879 TODO
4880 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004881 case XPATH_NODESET:
4882 case XPATH_XSLT_TREE:
4883 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004884 }
4885 break;
4886 case XPATH_USERS:
4887 case XPATH_POINT:
4888 case XPATH_RANGE:
4889 case XPATH_LOCATIONSET:
4890 TODO
4891 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004892 case XPATH_NODESET:
4893 case XPATH_XSLT_TREE:
4894 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004895 }
4896 xmlXPathFreeObject(arg1);
4897 xmlXPathFreeObject(arg2);
4898 return(ret);
4899}
4900
William M. Brack0c022ad2002-07-12 00:56:01 +00004901/**
4902 * xmlXPathEqualValues:
4903 * @ctxt: the XPath Parser context
4904 *
4905 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4906 *
4907 * Returns 0 or 1 depending on the results of the test.
4908 */
4909int
4910xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4911 xmlXPathObjectPtr arg1, arg2, argtmp;
4912 int ret = 0;
4913
Daniel Veillard6128c012004-11-08 17:16:15 +00004914 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00004915 arg2 = valuePop(ctxt);
4916 arg1 = valuePop(ctxt);
4917 if ((arg1 == NULL) || (arg2 == NULL)) {
4918 if (arg1 != NULL)
4919 xmlXPathFreeObject(arg1);
4920 else
4921 xmlXPathFreeObject(arg2);
4922 XP_ERROR0(XPATH_INVALID_OPERAND);
4923 }
4924
4925 if (arg1 == arg2) {
4926#ifdef DEBUG_EXPR
4927 xmlGenericError(xmlGenericErrorContext,
4928 "Equal: by pointer\n");
4929#endif
4930 return(1);
4931 }
4932
4933 /*
4934 *If either argument is a nodeset, it's a 'special case'
4935 */
4936 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4937 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4938 /*
4939 *Hack it to assure arg1 is the nodeset
4940 */
4941 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4942 argtmp = arg2;
4943 arg2 = arg1;
4944 arg1 = argtmp;
4945 }
4946 switch (arg2->type) {
4947 case XPATH_UNDEFINED:
4948#ifdef DEBUG_EXPR
4949 xmlGenericError(xmlGenericErrorContext,
4950 "Equal: undefined\n");
4951#endif
4952 break;
4953 case XPATH_NODESET:
4954 case XPATH_XSLT_TREE:
4955 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4956 break;
4957 case XPATH_BOOLEAN:
4958 if ((arg1->nodesetval == NULL) ||
4959 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4960 else
4961 ret = 1;
4962 ret = (ret == arg2->boolval);
4963 break;
4964 case XPATH_NUMBER:
4965 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4966 break;
4967 case XPATH_STRING:
4968 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4969 break;
4970 case XPATH_USERS:
4971 case XPATH_POINT:
4972 case XPATH_RANGE:
4973 case XPATH_LOCATIONSET:
4974 TODO
4975 break;
4976 }
4977 xmlXPathFreeObject(arg1);
4978 xmlXPathFreeObject(arg2);
4979 return(ret);
4980 }
4981
4982 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4983}
4984
4985/**
4986 * xmlXPathNotEqualValues:
4987 * @ctxt: the XPath Parser context
4988 *
4989 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4990 *
4991 * Returns 0 or 1 depending on the results of the test.
4992 */
4993int
4994xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4995 xmlXPathObjectPtr arg1, arg2, argtmp;
4996 int ret = 0;
4997
Daniel Veillard6128c012004-11-08 17:16:15 +00004998 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00004999 arg2 = valuePop(ctxt);
5000 arg1 = valuePop(ctxt);
5001 if ((arg1 == NULL) || (arg2 == NULL)) {
5002 if (arg1 != NULL)
5003 xmlXPathFreeObject(arg1);
5004 else
5005 xmlXPathFreeObject(arg2);
5006 XP_ERROR0(XPATH_INVALID_OPERAND);
5007 }
5008
5009 if (arg1 == arg2) {
5010#ifdef DEBUG_EXPR
5011 xmlGenericError(xmlGenericErrorContext,
5012 "NotEqual: by pointer\n");
5013#endif
5014 return(0);
5015 }
5016
5017 /*
5018 *If either argument is a nodeset, it's a 'special case'
5019 */
5020 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5021 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5022 /*
5023 *Hack it to assure arg1 is the nodeset
5024 */
5025 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5026 argtmp = arg2;
5027 arg2 = arg1;
5028 arg1 = argtmp;
5029 }
5030 switch (arg2->type) {
5031 case XPATH_UNDEFINED:
5032#ifdef DEBUG_EXPR
5033 xmlGenericError(xmlGenericErrorContext,
5034 "NotEqual: undefined\n");
5035#endif
5036 break;
5037 case XPATH_NODESET:
5038 case XPATH_XSLT_TREE:
5039 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
5040 break;
5041 case XPATH_BOOLEAN:
5042 if ((arg1->nodesetval == NULL) ||
5043 (arg1->nodesetval->nodeNr == 0)) ret = 0;
5044 else
5045 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00005046 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00005047 break;
5048 case XPATH_NUMBER:
5049 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5050 break;
5051 case XPATH_STRING:
5052 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
5053 break;
5054 case XPATH_USERS:
5055 case XPATH_POINT:
5056 case XPATH_RANGE:
5057 case XPATH_LOCATIONSET:
5058 TODO
5059 break;
5060 }
5061 xmlXPathFreeObject(arg1);
5062 xmlXPathFreeObject(arg2);
5063 return(ret);
5064 }
5065
5066 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5067}
Owen Taylor3473f882001-02-23 17:55:21 +00005068
5069/**
5070 * xmlXPathCompareValues:
5071 * @ctxt: the XPath Parser context
5072 * @inf: less than (1) or greater than (0)
5073 * @strict: is the comparison strict
5074 *
5075 * Implement the compare operation on XPath objects:
5076 * @arg1 < @arg2 (1, 1, ...
5077 * @arg1 <= @arg2 (1, 0, ...
5078 * @arg1 > @arg2 (0, 1, ...
5079 * @arg1 >= @arg2 (0, 0, ...
5080 *
5081 * When neither object to be compared is a node-set and the operator is
5082 * <=, <, >=, >, then the objects are compared by converted both objects
5083 * to numbers and comparing the numbers according to IEEE 754. The <
5084 * comparison will be true if and only if the first number is less than the
5085 * second number. The <= comparison will be true if and only if the first
5086 * number is less than or equal to the second number. The > comparison
5087 * will be true if and only if the first number is greater than the second
5088 * number. The >= comparison will be true if and only if the first number
5089 * is greater than or equal to the second number.
5090 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005091 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005092 */
5093int
5094xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005095 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005096 xmlXPathObjectPtr arg1, arg2;
5097
Daniel Veillard6128c012004-11-08 17:16:15 +00005098 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005099 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005100 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005101 if ((arg1 == NULL) || (arg2 == NULL)) {
5102 if (arg1 != NULL)
5103 xmlXPathFreeObject(arg1);
5104 else
5105 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005106 XP_ERROR0(XPATH_INVALID_OPERAND);
5107 }
5108
William M. Brack0c022ad2002-07-12 00:56:01 +00005109 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5110 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5111 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5112 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005113 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005114 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005115 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005116 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5117 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005118 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005119 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5120 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005121 }
5122 }
5123 return(ret);
5124 }
5125
5126 if (arg1->type != XPATH_NUMBER) {
5127 valuePush(ctxt, arg1);
5128 xmlXPathNumberFunction(ctxt, 1);
5129 arg1 = valuePop(ctxt);
5130 }
5131 if (arg1->type != XPATH_NUMBER) {
5132 xmlXPathFreeObject(arg1);
5133 xmlXPathFreeObject(arg2);
5134 XP_ERROR0(XPATH_INVALID_OPERAND);
5135 }
5136 if (arg2->type != XPATH_NUMBER) {
5137 valuePush(ctxt, arg2);
5138 xmlXPathNumberFunction(ctxt, 1);
5139 arg2 = valuePop(ctxt);
5140 }
5141 if (arg2->type != XPATH_NUMBER) {
5142 xmlXPathFreeObject(arg1);
5143 xmlXPathFreeObject(arg2);
5144 XP_ERROR0(XPATH_INVALID_OPERAND);
5145 }
5146 /*
5147 * Add tests for infinity and nan
5148 * => feedback on 3.4 for Inf and NaN
5149 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005150 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005151 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005152 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005153 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005154 arg1i=xmlXPathIsInf(arg1->floatval);
5155 arg2i=xmlXPathIsInf(arg2->floatval);
5156 if (inf && strict) {
5157 if ((arg1i == -1 && arg2i != -1) ||
5158 (arg2i == 1 && arg1i != 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 ret = 1;
5169 } else if (arg1i == 0 && arg2i == 0) {
5170 ret = (arg1->floatval <= arg2->floatval);
5171 } else {
5172 ret = 0;
5173 }
5174 }
5175 else if (!inf && strict) {
5176 if ((arg1i == 1 && arg2i != 1) ||
5177 (arg2i == -1 && arg1i != -1)) {
5178 ret = 1;
5179 } else if (arg1i == 0 && arg2i == 0) {
5180 ret = (arg1->floatval > arg2->floatval);
5181 } else {
5182 ret = 0;
5183 }
5184 }
5185 else if (!inf && !strict) {
5186 if (arg1i == 1 || arg2i == -1) {
5187 ret = 1;
5188 } else if (arg1i == 0 && arg2i == 0) {
5189 ret = (arg1->floatval >= arg2->floatval);
5190 } else {
5191 ret = 0;
5192 }
5193 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005194 }
Owen Taylor3473f882001-02-23 17:55:21 +00005195 xmlXPathFreeObject(arg1);
5196 xmlXPathFreeObject(arg2);
5197 return(ret);
5198}
5199
5200/**
5201 * xmlXPathValueFlipSign:
5202 * @ctxt: the XPath Parser context
5203 *
5204 * Implement the unary - operation on an XPath object
5205 * The numeric operators convert their operands to numbers as if
5206 * by calling the number function.
5207 */
5208void
5209xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005210 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005211 CAST_TO_NUMBER;
5212 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005213 if (xmlXPathIsNaN(ctxt->value->floatval))
5214 ctxt->value->floatval=xmlXPathNAN;
5215 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5216 ctxt->value->floatval=xmlXPathNINF;
5217 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5218 ctxt->value->floatval=xmlXPathPINF;
5219 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005220 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5221 ctxt->value->floatval = xmlXPathNZERO;
5222 else
5223 ctxt->value->floatval = 0;
5224 }
5225 else
5226 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005227}
5228
5229/**
5230 * xmlXPathAddValues:
5231 * @ctxt: the XPath Parser context
5232 *
5233 * Implement the add operation on XPath objects:
5234 * The numeric operators convert their operands to numbers as if
5235 * by calling the number function.
5236 */
5237void
5238xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5239 xmlXPathObjectPtr arg;
5240 double val;
5241
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005242 arg = valuePop(ctxt);
5243 if (arg == NULL)
5244 XP_ERROR(XPATH_INVALID_OPERAND);
5245 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005246 xmlXPathFreeObject(arg);
5247
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005248 CAST_TO_NUMBER;
5249 CHECK_TYPE(XPATH_NUMBER);
5250 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005251}
5252
5253/**
5254 * xmlXPathSubValues:
5255 * @ctxt: the XPath Parser context
5256 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005257 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005258 * The numeric operators convert their operands to numbers as if
5259 * by calling the number function.
5260 */
5261void
5262xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5263 xmlXPathObjectPtr arg;
5264 double val;
5265
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005266 arg = valuePop(ctxt);
5267 if (arg == NULL)
5268 XP_ERROR(XPATH_INVALID_OPERAND);
5269 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005270 xmlXPathFreeObject(arg);
5271
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005272 CAST_TO_NUMBER;
5273 CHECK_TYPE(XPATH_NUMBER);
5274 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005275}
5276
5277/**
5278 * xmlXPathMultValues:
5279 * @ctxt: the XPath Parser context
5280 *
5281 * Implement the multiply operation on XPath objects:
5282 * The numeric operators convert their operands to numbers as if
5283 * by calling the number function.
5284 */
5285void
5286xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5287 xmlXPathObjectPtr arg;
5288 double val;
5289
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005290 arg = valuePop(ctxt);
5291 if (arg == NULL)
5292 XP_ERROR(XPATH_INVALID_OPERAND);
5293 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005294 xmlXPathFreeObject(arg);
5295
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005296 CAST_TO_NUMBER;
5297 CHECK_TYPE(XPATH_NUMBER);
5298 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005299}
5300
5301/**
5302 * xmlXPathDivValues:
5303 * @ctxt: the XPath Parser context
5304 *
5305 * Implement the div operation on XPath objects @arg1 / @arg2:
5306 * The numeric operators convert their operands to numbers as if
5307 * by calling the number function.
5308 */
5309void
5310xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5311 xmlXPathObjectPtr arg;
5312 double val;
5313
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005314 arg = valuePop(ctxt);
5315 if (arg == NULL)
5316 XP_ERROR(XPATH_INVALID_OPERAND);
5317 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005318 xmlXPathFreeObject(arg);
5319
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005320 CAST_TO_NUMBER;
5321 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005322 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5323 ctxt->value->floatval = xmlXPathNAN;
5324 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005325 if (ctxt->value->floatval == 0)
5326 ctxt->value->floatval = xmlXPathNAN;
5327 else if (ctxt->value->floatval > 0)
5328 ctxt->value->floatval = xmlXPathNINF;
5329 else if (ctxt->value->floatval < 0)
5330 ctxt->value->floatval = xmlXPathPINF;
5331 }
5332 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005333 if (ctxt->value->floatval == 0)
5334 ctxt->value->floatval = xmlXPathNAN;
5335 else if (ctxt->value->floatval > 0)
5336 ctxt->value->floatval = xmlXPathPINF;
5337 else if (ctxt->value->floatval < 0)
5338 ctxt->value->floatval = xmlXPathNINF;
5339 } else
5340 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005341}
5342
5343/**
5344 * xmlXPathModValues:
5345 * @ctxt: the XPath Parser context
5346 *
5347 * Implement the mod operation on XPath objects: @arg1 / @arg2
5348 * The numeric operators convert their operands to numbers as if
5349 * by calling the number function.
5350 */
5351void
5352xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5353 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005354 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005355
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005356 arg = valuePop(ctxt);
5357 if (arg == NULL)
5358 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005359 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005360 xmlXPathFreeObject(arg);
5361
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005362 CAST_TO_NUMBER;
5363 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005364 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005365 if (arg2 == 0)
5366 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005367 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005368 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005369 }
Owen Taylor3473f882001-02-23 17:55:21 +00005370}
5371
5372/************************************************************************
5373 * *
5374 * The traversal functions *
5375 * *
5376 ************************************************************************/
5377
Owen Taylor3473f882001-02-23 17:55:21 +00005378/*
5379 * A traversal function enumerates nodes along an axis.
5380 * Initially it must be called with NULL, and it indicates
5381 * termination on the axis by returning NULL.
5382 */
5383typedef xmlNodePtr (*xmlXPathTraversalFunction)
5384 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5385
5386/**
5387 * xmlXPathNextSelf:
5388 * @ctxt: the XPath Parser context
5389 * @cur: the current node in the traversal
5390 *
5391 * Traversal function for the "self" direction
5392 * The self axis contains just the context node itself
5393 *
5394 * Returns the next element following that axis
5395 */
5396xmlNodePtr
5397xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005398 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005399 if (cur == NULL)
5400 return(ctxt->context->node);
5401 return(NULL);
5402}
5403
5404/**
5405 * xmlXPathNextChild:
5406 * @ctxt: the XPath Parser context
5407 * @cur: the current node in the traversal
5408 *
5409 * Traversal function for the "child" direction
5410 * The child axis contains the children of the context node in document order.
5411 *
5412 * Returns the next element following that axis
5413 */
5414xmlNodePtr
5415xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005416 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005417 if (cur == NULL) {
5418 if (ctxt->context->node == NULL) return(NULL);
5419 switch (ctxt->context->node->type) {
5420 case XML_ELEMENT_NODE:
5421 case XML_TEXT_NODE:
5422 case XML_CDATA_SECTION_NODE:
5423 case XML_ENTITY_REF_NODE:
5424 case XML_ENTITY_NODE:
5425 case XML_PI_NODE:
5426 case XML_COMMENT_NODE:
5427 case XML_NOTATION_NODE:
5428 case XML_DTD_NODE:
5429 return(ctxt->context->node->children);
5430 case XML_DOCUMENT_NODE:
5431 case XML_DOCUMENT_TYPE_NODE:
5432 case XML_DOCUMENT_FRAG_NODE:
5433 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005434#ifdef LIBXML_DOCB_ENABLED
5435 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005436#endif
5437 return(((xmlDocPtr) ctxt->context->node)->children);
5438 case XML_ELEMENT_DECL:
5439 case XML_ATTRIBUTE_DECL:
5440 case XML_ENTITY_DECL:
5441 case XML_ATTRIBUTE_NODE:
5442 case XML_NAMESPACE_DECL:
5443 case XML_XINCLUDE_START:
5444 case XML_XINCLUDE_END:
5445 return(NULL);
5446 }
5447 return(NULL);
5448 }
5449 if ((cur->type == XML_DOCUMENT_NODE) ||
5450 (cur->type == XML_HTML_DOCUMENT_NODE))
5451 return(NULL);
5452 return(cur->next);
5453}
5454
5455/**
5456 * xmlXPathNextDescendant:
5457 * @ctxt: the XPath Parser context
5458 * @cur: the current node in the traversal
5459 *
5460 * Traversal function for the "descendant" direction
5461 * the descendant axis contains the descendants of the context node in document
5462 * order; a descendant is a child or a child of a child and so on.
5463 *
5464 * Returns the next element following that axis
5465 */
5466xmlNodePtr
5467xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005468 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005469 if (cur == NULL) {
5470 if (ctxt->context->node == NULL)
5471 return(NULL);
5472 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5473 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5474 return(NULL);
5475
5476 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5477 return(ctxt->context->doc->children);
5478 return(ctxt->context->node->children);
5479 }
5480
Daniel Veillard567e1b42001-08-01 15:53:47 +00005481 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005482 /*
5483 * Do not descend on entities declarations
5484 */
5485 if (cur->children->type != XML_ENTITY_DECL) {
5486 cur = cur->children;
5487 /*
5488 * Skip DTDs
5489 */
5490 if (cur->type != XML_DTD_NODE)
5491 return(cur);
5492 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005493 }
5494
5495 if (cur == ctxt->context->node) return(NULL);
5496
Daniel Veillard68e9e742002-11-16 15:35:11 +00005497 while (cur->next != NULL) {
5498 cur = cur->next;
5499 if ((cur->type != XML_ENTITY_DECL) &&
5500 (cur->type != XML_DTD_NODE))
5501 return(cur);
5502 }
Owen Taylor3473f882001-02-23 17:55:21 +00005503
5504 do {
5505 cur = cur->parent;
5506 if (cur == NULL) return(NULL);
5507 if (cur == ctxt->context->node) return(NULL);
5508 if (cur->next != NULL) {
5509 cur = cur->next;
5510 return(cur);
5511 }
5512 } while (cur != NULL);
5513 return(cur);
5514}
5515
5516/**
5517 * xmlXPathNextDescendantOrSelf:
5518 * @ctxt: the XPath Parser context
5519 * @cur: the current node in the traversal
5520 *
5521 * Traversal function for the "descendant-or-self" direction
5522 * the descendant-or-self axis contains the context node and the descendants
5523 * of the context node in document order; thus the context node is the first
5524 * node on the axis, and the first child of the context node is the second node
5525 * on the axis
5526 *
5527 * Returns the next element following that axis
5528 */
5529xmlNodePtr
5530xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005531 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005532 if (cur == NULL) {
5533 if (ctxt->context->node == NULL)
5534 return(NULL);
5535 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5536 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5537 return(NULL);
5538 return(ctxt->context->node);
5539 }
5540
5541 return(xmlXPathNextDescendant(ctxt, cur));
5542}
5543
5544/**
5545 * xmlXPathNextParent:
5546 * @ctxt: the XPath Parser context
5547 * @cur: the current node in the traversal
5548 *
5549 * Traversal function for the "parent" direction
5550 * The parent axis contains the parent of the context node, if there is one.
5551 *
5552 * Returns the next element following that axis
5553 */
5554xmlNodePtr
5555xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005556 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005557 /*
5558 * the parent of an attribute or namespace node is the element
5559 * to which the attribute or namespace node is attached
5560 * Namespace handling !!!
5561 */
5562 if (cur == NULL) {
5563 if (ctxt->context->node == NULL) return(NULL);
5564 switch (ctxt->context->node->type) {
5565 case XML_ELEMENT_NODE:
5566 case XML_TEXT_NODE:
5567 case XML_CDATA_SECTION_NODE:
5568 case XML_ENTITY_REF_NODE:
5569 case XML_ENTITY_NODE:
5570 case XML_PI_NODE:
5571 case XML_COMMENT_NODE:
5572 case XML_NOTATION_NODE:
5573 case XML_DTD_NODE:
5574 case XML_ELEMENT_DECL:
5575 case XML_ATTRIBUTE_DECL:
5576 case XML_XINCLUDE_START:
5577 case XML_XINCLUDE_END:
5578 case XML_ENTITY_DECL:
5579 if (ctxt->context->node->parent == NULL)
5580 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005581 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005582 ((ctxt->context->node->parent->name[0] == ' ') ||
5583 (xmlStrEqual(ctxt->context->node->parent->name,
5584 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005585 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005586 return(ctxt->context->node->parent);
5587 case XML_ATTRIBUTE_NODE: {
5588 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5589
5590 return(att->parent);
5591 }
5592 case XML_DOCUMENT_NODE:
5593 case XML_DOCUMENT_TYPE_NODE:
5594 case XML_DOCUMENT_FRAG_NODE:
5595 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005596#ifdef LIBXML_DOCB_ENABLED
5597 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005598#endif
5599 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005600 case XML_NAMESPACE_DECL: {
5601 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5602
5603 if ((ns->next != NULL) &&
5604 (ns->next->type != XML_NAMESPACE_DECL))
5605 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005606 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005607 }
Owen Taylor3473f882001-02-23 17:55:21 +00005608 }
5609 }
5610 return(NULL);
5611}
5612
5613/**
5614 * xmlXPathNextAncestor:
5615 * @ctxt: the XPath Parser context
5616 * @cur: the current node in the traversal
5617 *
5618 * Traversal function for the "ancestor" direction
5619 * the ancestor axis contains the ancestors of the context node; the ancestors
5620 * of the context node consist of the parent of context node and the parent's
5621 * parent and so on; the nodes are ordered in reverse document order; thus the
5622 * parent is the first node on the axis, and the parent's parent is the second
5623 * node on the axis
5624 *
5625 * Returns the next element following that axis
5626 */
5627xmlNodePtr
5628xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005629 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005630 /*
5631 * the parent of an attribute or namespace node is the element
5632 * to which the attribute or namespace node is attached
5633 * !!!!!!!!!!!!!
5634 */
5635 if (cur == NULL) {
5636 if (ctxt->context->node == NULL) return(NULL);
5637 switch (ctxt->context->node->type) {
5638 case XML_ELEMENT_NODE:
5639 case XML_TEXT_NODE:
5640 case XML_CDATA_SECTION_NODE:
5641 case XML_ENTITY_REF_NODE:
5642 case XML_ENTITY_NODE:
5643 case XML_PI_NODE:
5644 case XML_COMMENT_NODE:
5645 case XML_DTD_NODE:
5646 case XML_ELEMENT_DECL:
5647 case XML_ATTRIBUTE_DECL:
5648 case XML_ENTITY_DECL:
5649 case XML_NOTATION_NODE:
5650 case XML_XINCLUDE_START:
5651 case XML_XINCLUDE_END:
5652 if (ctxt->context->node->parent == NULL)
5653 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005654 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005655 ((ctxt->context->node->parent->name[0] == ' ') ||
5656 (xmlStrEqual(ctxt->context->node->parent->name,
5657 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005658 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005659 return(ctxt->context->node->parent);
5660 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005661 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005662
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005663 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005664 }
5665 case XML_DOCUMENT_NODE:
5666 case XML_DOCUMENT_TYPE_NODE:
5667 case XML_DOCUMENT_FRAG_NODE:
5668 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005669#ifdef LIBXML_DOCB_ENABLED
5670 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005671#endif
5672 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005673 case XML_NAMESPACE_DECL: {
5674 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5675
5676 if ((ns->next != NULL) &&
5677 (ns->next->type != XML_NAMESPACE_DECL))
5678 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005679 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005680 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005681 }
Owen Taylor3473f882001-02-23 17:55:21 +00005682 }
5683 return(NULL);
5684 }
5685 if (cur == ctxt->context->doc->children)
5686 return((xmlNodePtr) ctxt->context->doc);
5687 if (cur == (xmlNodePtr) ctxt->context->doc)
5688 return(NULL);
5689 switch (cur->type) {
5690 case XML_ELEMENT_NODE:
5691 case XML_TEXT_NODE:
5692 case XML_CDATA_SECTION_NODE:
5693 case XML_ENTITY_REF_NODE:
5694 case XML_ENTITY_NODE:
5695 case XML_PI_NODE:
5696 case XML_COMMENT_NODE:
5697 case XML_NOTATION_NODE:
5698 case XML_DTD_NODE:
5699 case XML_ELEMENT_DECL:
5700 case XML_ATTRIBUTE_DECL:
5701 case XML_ENTITY_DECL:
5702 case XML_XINCLUDE_START:
5703 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005704 if (cur->parent == NULL)
5705 return(NULL);
5706 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005707 ((cur->parent->name[0] == ' ') ||
5708 (xmlStrEqual(cur->parent->name,
5709 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005710 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005711 return(cur->parent);
5712 case XML_ATTRIBUTE_NODE: {
5713 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5714
5715 return(att->parent);
5716 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005717 case XML_NAMESPACE_DECL: {
5718 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5719
5720 if ((ns->next != NULL) &&
5721 (ns->next->type != XML_NAMESPACE_DECL))
5722 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005723 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005724 return(NULL);
5725 }
Owen Taylor3473f882001-02-23 17:55:21 +00005726 case XML_DOCUMENT_NODE:
5727 case XML_DOCUMENT_TYPE_NODE:
5728 case XML_DOCUMENT_FRAG_NODE:
5729 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005730#ifdef LIBXML_DOCB_ENABLED
5731 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005732#endif
5733 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005734 }
5735 return(NULL);
5736}
5737
5738/**
5739 * xmlXPathNextAncestorOrSelf:
5740 * @ctxt: the XPath Parser context
5741 * @cur: the current node in the traversal
5742 *
5743 * Traversal function for the "ancestor-or-self" direction
5744 * he ancestor-or-self axis contains the context node and ancestors of
5745 * the context node in reverse document order; thus the context node is
5746 * the first node on the axis, and the context node's parent the second;
5747 * parent here is defined the same as with the parent axis.
5748 *
5749 * Returns the next element following that axis
5750 */
5751xmlNodePtr
5752xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005753 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005754 if (cur == NULL)
5755 return(ctxt->context->node);
5756 return(xmlXPathNextAncestor(ctxt, cur));
5757}
5758
5759/**
5760 * xmlXPathNextFollowingSibling:
5761 * @ctxt: the XPath Parser context
5762 * @cur: the current node in the traversal
5763 *
5764 * Traversal function for the "following-sibling" direction
5765 * The following-sibling axis contains the following siblings of the context
5766 * node in document order.
5767 *
5768 * Returns the next element following that axis
5769 */
5770xmlNodePtr
5771xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005772 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005773 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5774 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5775 return(NULL);
5776 if (cur == (xmlNodePtr) ctxt->context->doc)
5777 return(NULL);
5778 if (cur == NULL)
5779 return(ctxt->context->node->next);
5780 return(cur->next);
5781}
5782
5783/**
5784 * xmlXPathNextPrecedingSibling:
5785 * @ctxt: the XPath Parser context
5786 * @cur: the current node in the traversal
5787 *
5788 * Traversal function for the "preceding-sibling" direction
5789 * The preceding-sibling axis contains the preceding siblings of the context
5790 * node in reverse document order; the first preceding sibling is first on the
5791 * axis; the sibling preceding that node is the second on the axis and so on.
5792 *
5793 * Returns the next element following that axis
5794 */
5795xmlNodePtr
5796xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005797 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005798 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5799 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5800 return(NULL);
5801 if (cur == (xmlNodePtr) ctxt->context->doc)
5802 return(NULL);
5803 if (cur == NULL)
5804 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005805 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5806 cur = cur->prev;
5807 if (cur == NULL)
5808 return(ctxt->context->node->prev);
5809 }
Owen Taylor3473f882001-02-23 17:55:21 +00005810 return(cur->prev);
5811}
5812
5813/**
5814 * xmlXPathNextFollowing:
5815 * @ctxt: the XPath Parser context
5816 * @cur: the current node in the traversal
5817 *
5818 * Traversal function for the "following" direction
5819 * The following axis contains all nodes in the same document as the context
5820 * node that are after the context node in document order, excluding any
5821 * descendants and excluding attribute nodes and namespace nodes; the nodes
5822 * are ordered in document order
5823 *
5824 * Returns the next element following that axis
5825 */
5826xmlNodePtr
5827xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005828 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005829 if (cur != NULL && cur->children != NULL)
5830 return cur->children ;
5831 if (cur == NULL) cur = ctxt->context->node;
5832 if (cur == NULL) return(NULL) ; /* ERROR */
5833 if (cur->next != NULL) return(cur->next) ;
5834 do {
5835 cur = cur->parent;
5836 if (cur == NULL) return(NULL);
5837 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5838 if (cur->next != NULL) return(cur->next);
5839 } while (cur != NULL);
5840 return(cur);
5841}
5842
5843/*
5844 * xmlXPathIsAncestor:
5845 * @ancestor: the ancestor node
5846 * @node: the current node
5847 *
5848 * Check that @ancestor is a @node's ancestor
5849 *
5850 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5851 */
5852static int
5853xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5854 if ((ancestor == NULL) || (node == NULL)) return(0);
5855 /* nodes need to be in the same document */
5856 if (ancestor->doc != node->doc) return(0);
5857 /* avoid searching if ancestor or node is the root node */
5858 if (ancestor == (xmlNodePtr) node->doc) return(1);
5859 if (node == (xmlNodePtr) ancestor->doc) return(0);
5860 while (node->parent != NULL) {
5861 if (node->parent == ancestor)
5862 return(1);
5863 node = node->parent;
5864 }
5865 return(0);
5866}
5867
5868/**
5869 * xmlXPathNextPreceding:
5870 * @ctxt: the XPath Parser context
5871 * @cur: the current node in the traversal
5872 *
5873 * Traversal function for the "preceding" direction
5874 * the preceding axis contains all nodes in the same document as the context
5875 * node that are before the context node in document order, excluding any
5876 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5877 * ordered in reverse document order
5878 *
5879 * Returns the next element following that axis
5880 */
5881xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005882xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5883{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005884 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005885 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005886 cur = ctxt->context->node;
5887 if (cur == NULL)
5888 return (NULL);
5889 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5890 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005891 do {
5892 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005893 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5894 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005895 }
5896
5897 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005898 if (cur == NULL)
5899 return (NULL);
5900 if (cur == ctxt->context->doc->children)
5901 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005902 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005903 return (cur);
5904}
5905
5906/**
5907 * xmlXPathNextPrecedingInternal:
5908 * @ctxt: the XPath Parser context
5909 * @cur: the current node in the traversal
5910 *
5911 * Traversal function for the "preceding" direction
5912 * the preceding axis contains all nodes in the same document as the context
5913 * node that are before the context node in document order, excluding any
5914 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5915 * ordered in reverse document order
5916 * This is a faster implementation but internal only since it requires a
5917 * state kept in the parser context: ctxt->ancestor.
5918 *
5919 * Returns the next element following that axis
5920 */
5921static xmlNodePtr
5922xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5923 xmlNodePtr cur)
5924{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005925 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005926 if (cur == NULL) {
5927 cur = ctxt->context->node;
5928 if (cur == NULL)
5929 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005930 if (cur->type == XML_NAMESPACE_DECL)
5931 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005932 ctxt->ancestor = cur->parent;
5933 }
5934 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5935 cur = cur->prev;
5936 while (cur->prev == NULL) {
5937 cur = cur->parent;
5938 if (cur == NULL)
5939 return (NULL);
5940 if (cur == ctxt->context->doc->children)
5941 return (NULL);
5942 if (cur != ctxt->ancestor)
5943 return (cur);
5944 ctxt->ancestor = cur->parent;
5945 }
5946 cur = cur->prev;
5947 while (cur->last != NULL)
5948 cur = cur->last;
5949 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005950}
5951
5952/**
5953 * xmlXPathNextNamespace:
5954 * @ctxt: the XPath Parser context
5955 * @cur: the current attribute in the traversal
5956 *
5957 * Traversal function for the "namespace" direction
5958 * the namespace axis contains the namespace nodes of the context node;
5959 * the order of nodes on this axis is implementation-defined; the axis will
5960 * be empty unless the context node is an element
5961 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005962 * We keep the XML namespace node at the end of the list.
5963 *
Owen Taylor3473f882001-02-23 17:55:21 +00005964 * Returns the next element following that axis
5965 */
5966xmlNodePtr
5967xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005968 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005969 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005970 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005971 if (ctxt->context->tmpNsList != NULL)
5972 xmlFree(ctxt->context->tmpNsList);
5973 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005974 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005975 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005976 if (ctxt->context->tmpNsList != NULL) {
5977 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5978 ctxt->context->tmpNsNr++;
5979 }
5980 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005981 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005982 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005983 if (ctxt->context->tmpNsNr > 0) {
5984 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5985 } else {
5986 if (ctxt->context->tmpNsList != NULL)
5987 xmlFree(ctxt->context->tmpNsList);
5988 ctxt->context->tmpNsList = NULL;
5989 return(NULL);
5990 }
Owen Taylor3473f882001-02-23 17:55:21 +00005991}
5992
5993/**
5994 * xmlXPathNextAttribute:
5995 * @ctxt: the XPath Parser context
5996 * @cur: the current attribute in the traversal
5997 *
5998 * Traversal function for the "attribute" direction
5999 * TODO: support DTD inherited default attributes
6000 *
6001 * Returns the next element following that axis
6002 */
6003xmlNodePtr
6004xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006005 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00006006 if (ctxt->context->node == NULL)
6007 return(NULL);
6008 if (ctxt->context->node->type != XML_ELEMENT_NODE)
6009 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006010 if (cur == NULL) {
6011 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6012 return(NULL);
6013 return((xmlNodePtr)ctxt->context->node->properties);
6014 }
6015 return((xmlNodePtr)cur->next);
6016}
6017
6018/************************************************************************
6019 * *
6020 * NodeTest Functions *
6021 * *
6022 ************************************************************************/
6023
Owen Taylor3473f882001-02-23 17:55:21 +00006024#define IS_FUNCTION 200
6025
Owen Taylor3473f882001-02-23 17:55:21 +00006026
6027/************************************************************************
6028 * *
6029 * Implicit tree core function library *
6030 * *
6031 ************************************************************************/
6032
6033/**
6034 * xmlXPathRoot:
6035 * @ctxt: the XPath Parser context
6036 *
6037 * Initialize the context to the root of the document
6038 */
6039void
6040xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006041 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006042 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
6043 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6044}
6045
6046/************************************************************************
6047 * *
6048 * The explicit core function library *
6049 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
6050 * *
6051 ************************************************************************/
6052
6053
6054/**
6055 * xmlXPathLastFunction:
6056 * @ctxt: the XPath Parser context
6057 * @nargs: the number of arguments
6058 *
6059 * Implement the last() XPath function
6060 * number last()
6061 * The last function returns the number of nodes in the context node list.
6062 */
6063void
6064xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6065 CHECK_ARITY(0);
6066 if (ctxt->context->contextSize >= 0) {
6067 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
6068#ifdef DEBUG_EXPR
6069 xmlGenericError(xmlGenericErrorContext,
6070 "last() : %d\n", ctxt->context->contextSize);
6071#endif
6072 } else {
6073 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6074 }
6075}
6076
6077/**
6078 * xmlXPathPositionFunction:
6079 * @ctxt: the XPath Parser context
6080 * @nargs: the number of arguments
6081 *
6082 * Implement the position() XPath function
6083 * number position()
6084 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006085 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00006086 * will be equal to last().
6087 */
6088void
6089xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6090 CHECK_ARITY(0);
6091 if (ctxt->context->proximityPosition >= 0) {
6092 valuePush(ctxt,
6093 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6094#ifdef DEBUG_EXPR
6095 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6096 ctxt->context->proximityPosition);
6097#endif
6098 } else {
6099 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6100 }
6101}
6102
6103/**
6104 * xmlXPathCountFunction:
6105 * @ctxt: the XPath Parser context
6106 * @nargs: the number of arguments
6107 *
6108 * Implement the count() XPath function
6109 * number count(node-set)
6110 */
6111void
6112xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6113 xmlXPathObjectPtr cur;
6114
6115 CHECK_ARITY(1);
6116 if ((ctxt->value == NULL) ||
6117 ((ctxt->value->type != XPATH_NODESET) &&
6118 (ctxt->value->type != XPATH_XSLT_TREE)))
6119 XP_ERROR(XPATH_INVALID_TYPE);
6120 cur = valuePop(ctxt);
6121
Daniel Veillard911f49a2001-04-07 15:39:35 +00006122 if ((cur == NULL) || (cur->nodesetval == NULL))
6123 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006124 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006125 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006126 } else {
6127 if ((cur->nodesetval->nodeNr != 1) ||
6128 (cur->nodesetval->nodeTab == NULL)) {
6129 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6130 } else {
6131 xmlNodePtr tmp;
6132 int i = 0;
6133
6134 tmp = cur->nodesetval->nodeTab[0];
6135 if (tmp != NULL) {
6136 tmp = tmp->children;
6137 while (tmp != NULL) {
6138 tmp = tmp->next;
6139 i++;
6140 }
6141 }
6142 valuePush(ctxt, xmlXPathNewFloat((double) i));
6143 }
6144 }
Owen Taylor3473f882001-02-23 17:55:21 +00006145 xmlXPathFreeObject(cur);
6146}
6147
6148/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006149 * xmlXPathGetElementsByIds:
6150 * @doc: the document
6151 * @ids: a whitespace separated list of IDs
6152 *
6153 * Selects elements by their unique ID.
6154 *
6155 * Returns a node-set of selected elements.
6156 */
6157static xmlNodeSetPtr
6158xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6159 xmlNodeSetPtr ret;
6160 const xmlChar *cur = ids;
6161 xmlChar *ID;
6162 xmlAttrPtr attr;
6163 xmlNodePtr elem = NULL;
6164
Daniel Veillard7a985a12003-07-06 17:57:42 +00006165 if (ids == NULL) return(NULL);
6166
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006167 ret = xmlXPathNodeSetCreate(NULL);
6168
William M. Brack76e95df2003-10-18 16:20:14 +00006169 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006170 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006171 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006172 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006173
6174 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006175 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00006176 /*
6177 * We used to check the fact that the value passed
6178 * was an NCName, but this generated much troubles for
6179 * me and Aleksey Sanin, people blatantly violated that
6180 * constaint, like Visa3D spec.
6181 * if (xmlValidateNCName(ID, 1) == 0)
6182 */
6183 attr = xmlGetID(doc, ID);
6184 if (attr != NULL) {
6185 if (attr->type == XML_ATTRIBUTE_NODE)
6186 elem = attr->parent;
6187 else if (attr->type == XML_ELEMENT_NODE)
6188 elem = (xmlNodePtr) attr;
6189 else
6190 elem = NULL;
6191 if (elem != NULL)
6192 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00006193 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006194 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006195 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006196
William M. Brack76e95df2003-10-18 16:20:14 +00006197 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006198 ids = cur;
6199 }
6200 return(ret);
6201}
6202
6203/**
Owen Taylor3473f882001-02-23 17:55:21 +00006204 * xmlXPathIdFunction:
6205 * @ctxt: the XPath Parser context
6206 * @nargs: the number of arguments
6207 *
6208 * Implement the id() XPath function
6209 * node-set id(object)
6210 * The id function selects elements by their unique ID
6211 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6212 * then the result is the union of the result of applying id to the
6213 * string value of each of the nodes in the argument node-set. When the
6214 * argument to id is of any other type, the argument is converted to a
6215 * string as if by a call to the string function; the string is split
6216 * into a whitespace-separated list of tokens (whitespace is any sequence
6217 * of characters matching the production S); the result is a node-set
6218 * containing the elements in the same document as the context node that
6219 * have a unique ID equal to any of the tokens in the list.
6220 */
6221void
6222xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006223 xmlChar *tokens;
6224 xmlNodeSetPtr ret;
6225 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006226
6227 CHECK_ARITY(1);
6228 obj = valuePop(ctxt);
6229 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006230 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006231 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006232 int i;
6233
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006234 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006235
Daniel Veillard911f49a2001-04-07 15:39:35 +00006236 if (obj->nodesetval != NULL) {
6237 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006238 tokens =
6239 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6240 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6241 ret = xmlXPathNodeSetMerge(ret, ns);
6242 xmlXPathFreeNodeSet(ns);
6243 if (tokens != NULL)
6244 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006245 }
Owen Taylor3473f882001-02-23 17:55:21 +00006246 }
6247
6248 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006249 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006250 return;
6251 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006252 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006253
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006254 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6255 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006256
Owen Taylor3473f882001-02-23 17:55:21 +00006257 xmlXPathFreeObject(obj);
6258 return;
6259}
6260
6261/**
6262 * xmlXPathLocalNameFunction:
6263 * @ctxt: the XPath Parser context
6264 * @nargs: the number of arguments
6265 *
6266 * Implement the local-name() XPath function
6267 * string local-name(node-set?)
6268 * The local-name function returns a string containing the local part
6269 * of the name of the node in the argument node-set that is first in
6270 * document order. If the node-set is empty or the first node has no
6271 * name, an empty string is returned. If the argument is omitted it
6272 * defaults to the context node.
6273 */
6274void
6275xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6276 xmlXPathObjectPtr cur;
6277
Daniel Veillarda82b1822004-11-08 16:24:57 +00006278 if (ctxt == NULL) return;
6279
Owen Taylor3473f882001-02-23 17:55:21 +00006280 if (nargs == 0) {
6281 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6282 nargs = 1;
6283 }
6284
6285 CHECK_ARITY(1);
6286 if ((ctxt->value == NULL) ||
6287 ((ctxt->value->type != XPATH_NODESET) &&
6288 (ctxt->value->type != XPATH_XSLT_TREE)))
6289 XP_ERROR(XPATH_INVALID_TYPE);
6290 cur = valuePop(ctxt);
6291
Daniel Veillard911f49a2001-04-07 15:39:35 +00006292 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006293 valuePush(ctxt, xmlXPathNewCString(""));
6294 } else {
6295 int i = 0; /* Should be first in document order !!!!! */
6296 switch (cur->nodesetval->nodeTab[i]->type) {
6297 case XML_ELEMENT_NODE:
6298 case XML_ATTRIBUTE_NODE:
6299 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006300 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6301 valuePush(ctxt, xmlXPathNewCString(""));
6302 else
6303 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006304 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6305 break;
6306 case XML_NAMESPACE_DECL:
6307 valuePush(ctxt, xmlXPathNewString(
6308 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6309 break;
6310 default:
6311 valuePush(ctxt, xmlXPathNewCString(""));
6312 }
6313 }
6314 xmlXPathFreeObject(cur);
6315}
6316
6317/**
6318 * xmlXPathNamespaceURIFunction:
6319 * @ctxt: the XPath Parser context
6320 * @nargs: the number of arguments
6321 *
6322 * Implement the namespace-uri() XPath function
6323 * string namespace-uri(node-set?)
6324 * The namespace-uri function returns a string containing the
6325 * namespace URI of the expanded name of the node in the argument
6326 * node-set that is first in document order. If the node-set is empty,
6327 * the first node has no name, or the expanded name has no namespace
6328 * URI, an empty string is returned. If the argument is omitted it
6329 * defaults to the context node.
6330 */
6331void
6332xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6333 xmlXPathObjectPtr cur;
6334
Daniel Veillarda82b1822004-11-08 16:24:57 +00006335 if (ctxt == NULL) return;
6336
Owen Taylor3473f882001-02-23 17:55:21 +00006337 if (nargs == 0) {
6338 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6339 nargs = 1;
6340 }
6341 CHECK_ARITY(1);
6342 if ((ctxt->value == NULL) ||
6343 ((ctxt->value->type != XPATH_NODESET) &&
6344 (ctxt->value->type != XPATH_XSLT_TREE)))
6345 XP_ERROR(XPATH_INVALID_TYPE);
6346 cur = valuePop(ctxt);
6347
Daniel Veillard911f49a2001-04-07 15:39:35 +00006348 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006349 valuePush(ctxt, xmlXPathNewCString(""));
6350 } else {
6351 int i = 0; /* Should be first in document order !!!!! */
6352 switch (cur->nodesetval->nodeTab[i]->type) {
6353 case XML_ELEMENT_NODE:
6354 case XML_ATTRIBUTE_NODE:
6355 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6356 valuePush(ctxt, xmlXPathNewCString(""));
6357 else
6358 valuePush(ctxt, xmlXPathNewString(
6359 cur->nodesetval->nodeTab[i]->ns->href));
6360 break;
6361 default:
6362 valuePush(ctxt, xmlXPathNewCString(""));
6363 }
6364 }
6365 xmlXPathFreeObject(cur);
6366}
6367
6368/**
6369 * xmlXPathNameFunction:
6370 * @ctxt: the XPath Parser context
6371 * @nargs: the number of arguments
6372 *
6373 * Implement the name() XPath function
6374 * string name(node-set?)
6375 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006376 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006377 * order. The QName must represent the name with respect to the namespace
6378 * declarations in effect on the node whose name is being represented.
6379 * Typically, this will be the form in which the name occurred in the XML
6380 * source. This need not be the case if there are namespace declarations
6381 * in effect on the node that associate multiple prefixes with the same
6382 * namespace. However, an implementation may include information about
6383 * the original prefix in its representation of nodes; in this case, an
6384 * implementation can ensure that the returned string is always the same
6385 * as the QName used in the XML source. If the argument it omitted it
6386 * defaults to the context node.
6387 * Libxml keep the original prefix so the "real qualified name" used is
6388 * returned.
6389 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006390static void
Daniel Veillard04383752001-07-08 14:27:15 +00006391xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6392{
Owen Taylor3473f882001-02-23 17:55:21 +00006393 xmlXPathObjectPtr cur;
6394
6395 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006396 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6397 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006398 }
6399
6400 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006401 if ((ctxt->value == NULL) ||
6402 ((ctxt->value->type != XPATH_NODESET) &&
6403 (ctxt->value->type != XPATH_XSLT_TREE)))
6404 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006405 cur = valuePop(ctxt);
6406
Daniel Veillard911f49a2001-04-07 15:39:35 +00006407 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006408 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006409 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006410 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006411
Daniel Veillard04383752001-07-08 14:27:15 +00006412 switch (cur->nodesetval->nodeTab[i]->type) {
6413 case XML_ELEMENT_NODE:
6414 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006415 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6416 valuePush(ctxt, xmlXPathNewCString(""));
6417 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6418 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006419 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006420 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006421
Daniel Veillard652d8a92003-02-04 19:28:49 +00006422 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006423 xmlChar *fullname;
6424
6425 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6426 cur->nodesetval->nodeTab[i]->ns->prefix,
6427 NULL, 0);
6428 if (fullname == cur->nodesetval->nodeTab[i]->name)
6429 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6430 if (fullname == NULL) {
6431 XP_ERROR(XPATH_MEMORY_ERROR);
6432 }
6433 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006434 }
6435 break;
6436 default:
6437 valuePush(ctxt,
6438 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6439 xmlXPathLocalNameFunction(ctxt, 1);
6440 }
Owen Taylor3473f882001-02-23 17:55:21 +00006441 }
6442 xmlXPathFreeObject(cur);
6443}
6444
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006445
6446/**
Owen Taylor3473f882001-02-23 17:55:21 +00006447 * xmlXPathStringFunction:
6448 * @ctxt: the XPath Parser context
6449 * @nargs: the number of arguments
6450 *
6451 * Implement the string() XPath function
6452 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006453 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006454 * - A node-set is converted to a string by returning the value of
6455 * the node in the node-set that is first in document order.
6456 * If the node-set is empty, an empty string is returned.
6457 * - A number is converted to a string as follows
6458 * + NaN is converted to the string NaN
6459 * + positive zero is converted to the string 0
6460 * + negative zero is converted to the string 0
6461 * + positive infinity is converted to the string Infinity
6462 * + negative infinity is converted to the string -Infinity
6463 * + if the number is an integer, the number is represented in
6464 * decimal form as a Number with no decimal point and no leading
6465 * zeros, preceded by a minus sign (-) if the number is negative
6466 * + otherwise, the number is represented in decimal form as a
6467 * Number including a decimal point with at least one digit
6468 * before the decimal point and at least one digit after the
6469 * decimal point, preceded by a minus sign (-) if the number
6470 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006471 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006472 * before the decimal point; beyond the one required digit
6473 * after the decimal point there must be as many, but only as
6474 * many, more digits as are needed to uniquely distinguish the
6475 * number from all other IEEE 754 numeric values.
6476 * - The boolean false value is converted to the string false.
6477 * The boolean true value is converted to the string true.
6478 *
6479 * If the argument is omitted, it defaults to a node-set with the
6480 * context node as its only member.
6481 */
6482void
6483xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6484 xmlXPathObjectPtr cur;
6485
Daniel Veillarda82b1822004-11-08 16:24:57 +00006486 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006487 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006488 valuePush(ctxt,
6489 xmlXPathWrapString(
6490 xmlXPathCastNodeToString(ctxt->context->node)));
6491 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006492 }
6493
6494 CHECK_ARITY(1);
6495 cur = valuePop(ctxt);
6496 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006497 cur = xmlXPathConvertString(cur);
6498 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006499}
6500
6501/**
6502 * xmlXPathStringLengthFunction:
6503 * @ctxt: the XPath Parser context
6504 * @nargs: the number of arguments
6505 *
6506 * Implement the string-length() XPath function
6507 * number string-length(string?)
6508 * The string-length returns the number of characters in the string
6509 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6510 * the context node converted to a string, in other words the value
6511 * of the context node.
6512 */
6513void
6514xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6515 xmlXPathObjectPtr cur;
6516
6517 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006518 if ((ctxt == NULL) || (ctxt->context == NULL))
6519 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006520 if (ctxt->context->node == NULL) {
6521 valuePush(ctxt, xmlXPathNewFloat(0));
6522 } else {
6523 xmlChar *content;
6524
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006525 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006526 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006527 xmlFree(content);
6528 }
6529 return;
6530 }
6531 CHECK_ARITY(1);
6532 CAST_TO_STRING;
6533 CHECK_TYPE(XPATH_STRING);
6534 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006535 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006536 xmlXPathFreeObject(cur);
6537}
6538
6539/**
6540 * xmlXPathConcatFunction:
6541 * @ctxt: the XPath Parser context
6542 * @nargs: the number of arguments
6543 *
6544 * Implement the concat() XPath function
6545 * string concat(string, string, string*)
6546 * The concat function returns the concatenation of its arguments.
6547 */
6548void
6549xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6550 xmlXPathObjectPtr cur, newobj;
6551 xmlChar *tmp;
6552
Daniel Veillarda82b1822004-11-08 16:24:57 +00006553 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006554 if (nargs < 2) {
6555 CHECK_ARITY(2);
6556 }
6557
6558 CAST_TO_STRING;
6559 cur = valuePop(ctxt);
6560 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6561 xmlXPathFreeObject(cur);
6562 return;
6563 }
6564 nargs--;
6565
6566 while (nargs > 0) {
6567 CAST_TO_STRING;
6568 newobj = valuePop(ctxt);
6569 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6570 xmlXPathFreeObject(newobj);
6571 xmlXPathFreeObject(cur);
6572 XP_ERROR(XPATH_INVALID_TYPE);
6573 }
6574 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6575 newobj->stringval = cur->stringval;
6576 cur->stringval = tmp;
6577
6578 xmlXPathFreeObject(newobj);
6579 nargs--;
6580 }
6581 valuePush(ctxt, cur);
6582}
6583
6584/**
6585 * xmlXPathContainsFunction:
6586 * @ctxt: the XPath Parser context
6587 * @nargs: the number of arguments
6588 *
6589 * Implement the contains() XPath function
6590 * boolean contains(string, string)
6591 * The contains function returns true if the first argument string
6592 * contains the second argument string, and otherwise returns false.
6593 */
6594void
6595xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6596 xmlXPathObjectPtr hay, needle;
6597
6598 CHECK_ARITY(2);
6599 CAST_TO_STRING;
6600 CHECK_TYPE(XPATH_STRING);
6601 needle = valuePop(ctxt);
6602 CAST_TO_STRING;
6603 hay = valuePop(ctxt);
6604 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6605 xmlXPathFreeObject(hay);
6606 xmlXPathFreeObject(needle);
6607 XP_ERROR(XPATH_INVALID_TYPE);
6608 }
6609 if (xmlStrstr(hay->stringval, needle->stringval))
6610 valuePush(ctxt, xmlXPathNewBoolean(1));
6611 else
6612 valuePush(ctxt, xmlXPathNewBoolean(0));
6613 xmlXPathFreeObject(hay);
6614 xmlXPathFreeObject(needle);
6615}
6616
6617/**
6618 * xmlXPathStartsWithFunction:
6619 * @ctxt: the XPath Parser context
6620 * @nargs: the number of arguments
6621 *
6622 * Implement the starts-with() XPath function
6623 * boolean starts-with(string, string)
6624 * The starts-with function returns true if the first argument string
6625 * starts with the second argument string, and otherwise returns false.
6626 */
6627void
6628xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6629 xmlXPathObjectPtr hay, needle;
6630 int n;
6631
6632 CHECK_ARITY(2);
6633 CAST_TO_STRING;
6634 CHECK_TYPE(XPATH_STRING);
6635 needle = valuePop(ctxt);
6636 CAST_TO_STRING;
6637 hay = valuePop(ctxt);
6638 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6639 xmlXPathFreeObject(hay);
6640 xmlXPathFreeObject(needle);
6641 XP_ERROR(XPATH_INVALID_TYPE);
6642 }
6643 n = xmlStrlen(needle->stringval);
6644 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6645 valuePush(ctxt, xmlXPathNewBoolean(0));
6646 else
6647 valuePush(ctxt, xmlXPathNewBoolean(1));
6648 xmlXPathFreeObject(hay);
6649 xmlXPathFreeObject(needle);
6650}
6651
6652/**
6653 * xmlXPathSubstringFunction:
6654 * @ctxt: the XPath Parser context
6655 * @nargs: the number of arguments
6656 *
6657 * Implement the substring() XPath function
6658 * string substring(string, number, number?)
6659 * The substring function returns the substring of the first argument
6660 * starting at the position specified in the second argument with
6661 * length specified in the third argument. For example,
6662 * substring("12345",2,3) returns "234". If the third argument is not
6663 * specified, it returns the substring starting at the position specified
6664 * in the second argument and continuing to the end of the string. For
6665 * example, substring("12345",2) returns "2345". More precisely, each
6666 * character in the string (see [3.6 Strings]) is considered to have a
6667 * numeric position: the position of the first character is 1, the position
6668 * of the second character is 2 and so on. The returned substring contains
6669 * those characters for which the position of the character is greater than
6670 * or equal to the second argument and, if the third argument is specified,
6671 * less than the sum of the second and third arguments; the comparisons
6672 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6673 * - substring("12345", 1.5, 2.6) returns "234"
6674 * - substring("12345", 0, 3) returns "12"
6675 * - substring("12345", 0 div 0, 3) returns ""
6676 * - substring("12345", 1, 0 div 0) returns ""
6677 * - substring("12345", -42, 1 div 0) returns "12345"
6678 * - substring("12345", -1 div 0, 1 div 0) returns ""
6679 */
6680void
6681xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6682 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006683 double le=0, in;
6684 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006685 xmlChar *ret;
6686
Owen Taylor3473f882001-02-23 17:55:21 +00006687 if (nargs < 2) {
6688 CHECK_ARITY(2);
6689 }
6690 if (nargs > 3) {
6691 CHECK_ARITY(3);
6692 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006693 /*
6694 * take care of possible last (position) argument
6695 */
Owen Taylor3473f882001-02-23 17:55:21 +00006696 if (nargs == 3) {
6697 CAST_TO_NUMBER;
6698 CHECK_TYPE(XPATH_NUMBER);
6699 len = valuePop(ctxt);
6700 le = len->floatval;
6701 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006702 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006703
Owen Taylor3473f882001-02-23 17:55:21 +00006704 CAST_TO_NUMBER;
6705 CHECK_TYPE(XPATH_NUMBER);
6706 start = valuePop(ctxt);
6707 in = start->floatval;
6708 xmlXPathFreeObject(start);
6709 CAST_TO_STRING;
6710 CHECK_TYPE(XPATH_STRING);
6711 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006712 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006713
Daniel Veillard97ac1312001-05-30 19:14:17 +00006714 /*
6715 * If last pos not present, calculate last position
6716 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006717 if (nargs != 3) {
6718 le = (double)m;
6719 if (in < 1.0)
6720 in = 1.0;
6721 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006722
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006723 /* Need to check for the special cases where either
6724 * the index is NaN, the length is NaN, or both
6725 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006726 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006727 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006728 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006729 * To meet the requirements of the spec, the arguments
6730 * must be converted to integer format before
6731 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006732 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006733 * First we go to integer form, rounding up
6734 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006735 */
6736 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006737 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006738
Daniel Veillard9e412302002-06-10 15:59:44 +00006739 if (xmlXPathIsInf(le) == 1) {
6740 l = m;
6741 if (i < 1)
6742 i = 1;
6743 }
6744 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6745 l = 0;
6746 else {
6747 l = (int) le;
6748 if (((double)l)+0.5 <= le) l++;
6749 }
6750
6751 /* Now we normalize inidices */
6752 i -= 1;
6753 l += i;
6754 if (i < 0)
6755 i = 0;
6756 if (l > m)
6757 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006758
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006759 /* number of chars to copy */
6760 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006761
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006762 ret = xmlUTF8Strsub(str->stringval, i, l);
6763 }
6764 else {
6765 ret = NULL;
6766 }
6767
Owen Taylor3473f882001-02-23 17:55:21 +00006768 if (ret == NULL)
6769 valuePush(ctxt, xmlXPathNewCString(""));
6770 else {
6771 valuePush(ctxt, xmlXPathNewString(ret));
6772 xmlFree(ret);
6773 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006774
Owen Taylor3473f882001-02-23 17:55:21 +00006775 xmlXPathFreeObject(str);
6776}
6777
6778/**
6779 * xmlXPathSubstringBeforeFunction:
6780 * @ctxt: the XPath Parser context
6781 * @nargs: the number of arguments
6782 *
6783 * Implement the substring-before() XPath function
6784 * string substring-before(string, string)
6785 * The substring-before function returns the substring of the first
6786 * argument string that precedes the first occurrence of the second
6787 * argument string in the first argument string, or the empty string
6788 * if the first argument string does not contain the second argument
6789 * string. For example, substring-before("1999/04/01","/") returns 1999.
6790 */
6791void
6792xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6793 xmlXPathObjectPtr str;
6794 xmlXPathObjectPtr find;
6795 xmlBufferPtr target;
6796 const xmlChar *point;
6797 int offset;
6798
6799 CHECK_ARITY(2);
6800 CAST_TO_STRING;
6801 find = valuePop(ctxt);
6802 CAST_TO_STRING;
6803 str = valuePop(ctxt);
6804
6805 target = xmlBufferCreate();
6806 if (target) {
6807 point = xmlStrstr(str->stringval, find->stringval);
6808 if (point) {
6809 offset = (int)(point - str->stringval);
6810 xmlBufferAdd(target, str->stringval, offset);
6811 }
6812 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6813 xmlBufferFree(target);
6814 }
6815
6816 xmlXPathFreeObject(str);
6817 xmlXPathFreeObject(find);
6818}
6819
6820/**
6821 * xmlXPathSubstringAfterFunction:
6822 * @ctxt: the XPath Parser context
6823 * @nargs: the number of arguments
6824 *
6825 * Implement the substring-after() XPath function
6826 * string substring-after(string, string)
6827 * The substring-after function returns the substring of the first
6828 * argument string that follows the first occurrence of the second
6829 * argument string in the first argument string, or the empty stringi
6830 * if the first argument string does not contain the second argument
6831 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6832 * and substring-after("1999/04/01","19") returns 99/04/01.
6833 */
6834void
6835xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6836 xmlXPathObjectPtr str;
6837 xmlXPathObjectPtr find;
6838 xmlBufferPtr target;
6839 const xmlChar *point;
6840 int offset;
6841
6842 CHECK_ARITY(2);
6843 CAST_TO_STRING;
6844 find = valuePop(ctxt);
6845 CAST_TO_STRING;
6846 str = valuePop(ctxt);
6847
6848 target = xmlBufferCreate();
6849 if (target) {
6850 point = xmlStrstr(str->stringval, find->stringval);
6851 if (point) {
6852 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6853 xmlBufferAdd(target, &str->stringval[offset],
6854 xmlStrlen(str->stringval) - offset);
6855 }
6856 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6857 xmlBufferFree(target);
6858 }
6859
6860 xmlXPathFreeObject(str);
6861 xmlXPathFreeObject(find);
6862}
6863
6864/**
6865 * xmlXPathNormalizeFunction:
6866 * @ctxt: the XPath Parser context
6867 * @nargs: the number of arguments
6868 *
6869 * Implement the normalize-space() XPath function
6870 * string normalize-space(string?)
6871 * The normalize-space function returns the argument string with white
6872 * space normalized by stripping leading and trailing whitespace
6873 * and replacing sequences of whitespace characters by a single
6874 * space. Whitespace characters are the same allowed by the S production
6875 * in XML. If the argument is omitted, it defaults to the context
6876 * node converted to a string, in other words the value of the context node.
6877 */
6878void
6879xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6880 xmlXPathObjectPtr obj = NULL;
6881 xmlChar *source = NULL;
6882 xmlBufferPtr target;
6883 xmlChar blank;
6884
Daniel Veillarda82b1822004-11-08 16:24:57 +00006885 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006886 if (nargs == 0) {
6887 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006888 valuePush(ctxt,
6889 xmlXPathWrapString(
6890 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006891 nargs = 1;
6892 }
6893
6894 CHECK_ARITY(1);
6895 CAST_TO_STRING;
6896 CHECK_TYPE(XPATH_STRING);
6897 obj = valuePop(ctxt);
6898 source = obj->stringval;
6899
6900 target = xmlBufferCreate();
6901 if (target && source) {
6902
6903 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006904 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006905 source++;
6906
6907 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6908 blank = 0;
6909 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006910 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006911 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006912 } else {
6913 if (blank) {
6914 xmlBufferAdd(target, &blank, 1);
6915 blank = 0;
6916 }
6917 xmlBufferAdd(target, source, 1);
6918 }
6919 source++;
6920 }
6921
6922 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6923 xmlBufferFree(target);
6924 }
6925 xmlXPathFreeObject(obj);
6926}
6927
6928/**
6929 * xmlXPathTranslateFunction:
6930 * @ctxt: the XPath Parser context
6931 * @nargs: the number of arguments
6932 *
6933 * Implement the translate() XPath function
6934 * string translate(string, string, string)
6935 * The translate function returns the first argument string with
6936 * occurrences of characters in the second argument string replaced
6937 * by the character at the corresponding position in the third argument
6938 * string. For example, translate("bar","abc","ABC") returns the string
6939 * BAr. If there is a character in the second argument string with no
6940 * character at a corresponding position in the third argument string
6941 * (because the second argument string is longer than the third argument
6942 * string), then occurrences of that character in the first argument
6943 * string are removed. For example, translate("--aaa--","abc-","ABC")
6944 * returns "AAA". If a character occurs more than once in second
6945 * argument string, then the first occurrence determines the replacement
6946 * character. If the third argument string is longer than the second
6947 * argument string, then excess characters are ignored.
6948 */
6949void
6950xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006951 xmlXPathObjectPtr str;
6952 xmlXPathObjectPtr from;
6953 xmlXPathObjectPtr to;
6954 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006955 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006956 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00006957 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006958 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006959
Daniel Veillarde043ee12001-04-16 14:08:07 +00006960 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006961
Daniel Veillarde043ee12001-04-16 14:08:07 +00006962 CAST_TO_STRING;
6963 to = valuePop(ctxt);
6964 CAST_TO_STRING;
6965 from = valuePop(ctxt);
6966 CAST_TO_STRING;
6967 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006968
Daniel Veillarde043ee12001-04-16 14:08:07 +00006969 target = xmlBufferCreate();
6970 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006971 max = xmlUTF8Strlen(to->stringval);
6972 for (cptr = str->stringval; (ch=*cptr); ) {
6973 offset = xmlUTF8Strloc(from->stringval, cptr);
6974 if (offset >= 0) {
6975 if (offset < max) {
6976 point = xmlUTF8Strpos(to->stringval, offset);
6977 if (point)
6978 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6979 }
6980 } else
6981 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6982
6983 /* Step to next character in input */
6984 cptr++;
6985 if ( ch & 0x80 ) {
6986 /* if not simple ascii, verify proper format */
6987 if ( (ch & 0xc0) != 0xc0 ) {
6988 xmlGenericError(xmlGenericErrorContext,
6989 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6990 break;
6991 }
6992 /* then skip over remaining bytes for this char */
6993 while ( (ch <<= 1) & 0x80 )
6994 if ( (*cptr++ & 0xc0) != 0x80 ) {
6995 xmlGenericError(xmlGenericErrorContext,
6996 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6997 break;
6998 }
6999 if (ch & 0x80) /* must have had error encountered */
7000 break;
7001 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00007002 }
Owen Taylor3473f882001-02-23 17:55:21 +00007003 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00007004 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
7005 xmlBufferFree(target);
7006 xmlXPathFreeObject(str);
7007 xmlXPathFreeObject(from);
7008 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00007009}
7010
7011/**
7012 * xmlXPathBooleanFunction:
7013 * @ctxt: the XPath Parser context
7014 * @nargs: the number of arguments
7015 *
7016 * Implement the boolean() XPath function
7017 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00007018 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00007019 * - a number is true if and only if it is neither positive or
7020 * negative zero nor NaN
7021 * - a node-set is true if and only if it is non-empty
7022 * - a string is true if and only if its length is non-zero
7023 */
7024void
7025xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7026 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00007027
7028 CHECK_ARITY(1);
7029 cur = valuePop(ctxt);
7030 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007031 cur = xmlXPathConvertBoolean(cur);
7032 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007033}
7034
7035/**
7036 * xmlXPathNotFunction:
7037 * @ctxt: the XPath Parser context
7038 * @nargs: the number of arguments
7039 *
7040 * Implement the not() XPath function
7041 * boolean not(boolean)
7042 * The not function returns true if its argument is false,
7043 * and false otherwise.
7044 */
7045void
7046xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7047 CHECK_ARITY(1);
7048 CAST_TO_BOOLEAN;
7049 CHECK_TYPE(XPATH_BOOLEAN);
7050 ctxt->value->boolval = ! ctxt->value->boolval;
7051}
7052
7053/**
7054 * xmlXPathTrueFunction:
7055 * @ctxt: the XPath Parser context
7056 * @nargs: the number of arguments
7057 *
7058 * Implement the true() XPath function
7059 * boolean true()
7060 */
7061void
7062xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7063 CHECK_ARITY(0);
7064 valuePush(ctxt, xmlXPathNewBoolean(1));
7065}
7066
7067/**
7068 * xmlXPathFalseFunction:
7069 * @ctxt: the XPath Parser context
7070 * @nargs: the number of arguments
7071 *
7072 * Implement the false() XPath function
7073 * boolean false()
7074 */
7075void
7076xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7077 CHECK_ARITY(0);
7078 valuePush(ctxt, xmlXPathNewBoolean(0));
7079}
7080
7081/**
7082 * xmlXPathLangFunction:
7083 * @ctxt: the XPath Parser context
7084 * @nargs: the number of arguments
7085 *
7086 * Implement the lang() XPath function
7087 * boolean lang(string)
7088 * The lang function returns true or false depending on whether the
7089 * language of the context node as specified by xml:lang attributes
7090 * is the same as or is a sublanguage of the language specified by
7091 * the argument string. The language of the context node is determined
7092 * by the value of the xml:lang attribute on the context node, or, if
7093 * the context node has no xml:lang attribute, by the value of the
7094 * xml:lang attribute on the nearest ancestor of the context node that
7095 * has an xml:lang attribute. If there is no such attribute, then lang
7096 * returns false. If there is such an attribute, then lang returns
7097 * true if the attribute value is equal to the argument ignoring case,
7098 * or if there is some suffix starting with - such that the attribute
7099 * value is equal to the argument ignoring that suffix of the attribute
7100 * value and ignoring case.
7101 */
7102void
7103xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7104 xmlXPathObjectPtr val;
7105 const xmlChar *theLang;
7106 const xmlChar *lang;
7107 int ret = 0;
7108 int i;
7109
7110 CHECK_ARITY(1);
7111 CAST_TO_STRING;
7112 CHECK_TYPE(XPATH_STRING);
7113 val = valuePop(ctxt);
7114 lang = val->stringval;
7115 theLang = xmlNodeGetLang(ctxt->context->node);
7116 if ((theLang != NULL) && (lang != NULL)) {
7117 for (i = 0;lang[i] != 0;i++)
7118 if (toupper(lang[i]) != toupper(theLang[i]))
7119 goto not_equal;
7120 ret = 1;
7121 }
7122not_equal:
William M. Bracka59ddb52004-02-25 08:12:32 +00007123 xmlFree((void *)theLang);
Owen Taylor3473f882001-02-23 17:55:21 +00007124 xmlXPathFreeObject(val);
7125 valuePush(ctxt, xmlXPathNewBoolean(ret));
7126}
7127
7128/**
7129 * xmlXPathNumberFunction:
7130 * @ctxt: the XPath Parser context
7131 * @nargs: the number of arguments
7132 *
7133 * Implement the number() XPath function
7134 * number number(object?)
7135 */
7136void
7137xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7138 xmlXPathObjectPtr cur;
7139 double res;
7140
Daniel Veillarda82b1822004-11-08 16:24:57 +00007141 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007142 if (nargs == 0) {
7143 if (ctxt->context->node == NULL) {
7144 valuePush(ctxt, xmlXPathNewFloat(0.0));
7145 } else {
7146 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7147
7148 res = xmlXPathStringEvalNumber(content);
7149 valuePush(ctxt, xmlXPathNewFloat(res));
7150 xmlFree(content);
7151 }
7152 return;
7153 }
7154
7155 CHECK_ARITY(1);
7156 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007157 cur = xmlXPathConvertNumber(cur);
7158 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007159}
7160
7161/**
7162 * xmlXPathSumFunction:
7163 * @ctxt: the XPath Parser context
7164 * @nargs: the number of arguments
7165 *
7166 * Implement the sum() XPath function
7167 * number sum(node-set)
7168 * The sum function returns the sum of the values of the nodes in
7169 * the argument node-set.
7170 */
7171void
7172xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7173 xmlXPathObjectPtr cur;
7174 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007175 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007176
7177 CHECK_ARITY(1);
7178 if ((ctxt->value == NULL) ||
7179 ((ctxt->value->type != XPATH_NODESET) &&
7180 (ctxt->value->type != XPATH_XSLT_TREE)))
7181 XP_ERROR(XPATH_INVALID_TYPE);
7182 cur = valuePop(ctxt);
7183
William M. Brack08171912003-12-29 02:52:11 +00007184 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007185 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7186 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007187 }
7188 }
William M. Brack08171912003-12-29 02:52:11 +00007189 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007190 xmlXPathFreeObject(cur);
7191}
7192
7193/**
7194 * xmlXPathFloorFunction:
7195 * @ctxt: the XPath Parser context
7196 * @nargs: the number of arguments
7197 *
7198 * Implement the floor() XPath function
7199 * number floor(number)
7200 * The floor function returns the largest (closest to positive infinity)
7201 * number that is not greater than the argument and that is an integer.
7202 */
7203void
7204xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007205 double f;
7206
Owen Taylor3473f882001-02-23 17:55:21 +00007207 CHECK_ARITY(1);
7208 CAST_TO_NUMBER;
7209 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007210
7211 f = (double)((int) ctxt->value->floatval);
7212 if (f != ctxt->value->floatval) {
7213 if (ctxt->value->floatval > 0)
7214 ctxt->value->floatval = f;
7215 else
7216 ctxt->value->floatval = f - 1;
7217 }
Owen Taylor3473f882001-02-23 17:55:21 +00007218}
7219
7220/**
7221 * xmlXPathCeilingFunction:
7222 * @ctxt: the XPath Parser context
7223 * @nargs: the number of arguments
7224 *
7225 * Implement the ceiling() XPath function
7226 * number ceiling(number)
7227 * The ceiling function returns the smallest (closest to negative infinity)
7228 * number that is not less than the argument and that is an integer.
7229 */
7230void
7231xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7232 double f;
7233
7234 CHECK_ARITY(1);
7235 CAST_TO_NUMBER;
7236 CHECK_TYPE(XPATH_NUMBER);
7237
7238#if 0
7239 ctxt->value->floatval = ceil(ctxt->value->floatval);
7240#else
7241 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007242 if (f != ctxt->value->floatval) {
7243 if (ctxt->value->floatval > 0)
7244 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007245 else {
7246 if (ctxt->value->floatval < 0 && f == 0)
7247 ctxt->value->floatval = xmlXPathNZERO;
7248 else
7249 ctxt->value->floatval = f;
7250 }
7251
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007252 }
Owen Taylor3473f882001-02-23 17:55:21 +00007253#endif
7254}
7255
7256/**
7257 * xmlXPathRoundFunction:
7258 * @ctxt: the XPath Parser context
7259 * @nargs: the number of arguments
7260 *
7261 * Implement the round() XPath function
7262 * number round(number)
7263 * The round function returns the number that is closest to the
7264 * argument and that is an integer. If there are two such numbers,
7265 * then the one that is even is returned.
7266 */
7267void
7268xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7269 double f;
7270
7271 CHECK_ARITY(1);
7272 CAST_TO_NUMBER;
7273 CHECK_TYPE(XPATH_NUMBER);
7274
Daniel Veillardcda96922001-08-21 10:56:31 +00007275 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7276 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7277 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007278 (ctxt->value->floatval == 0.0))
7279 return;
7280
Owen Taylor3473f882001-02-23 17:55:21 +00007281 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007282 if (ctxt->value->floatval < 0) {
7283 if (ctxt->value->floatval < f - 0.5)
7284 ctxt->value->floatval = f - 1;
7285 else
7286 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007287 if (ctxt->value->floatval == 0)
7288 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007289 } else {
7290 if (ctxt->value->floatval < f + 0.5)
7291 ctxt->value->floatval = f;
7292 else
7293 ctxt->value->floatval = f + 1;
7294 }
Owen Taylor3473f882001-02-23 17:55:21 +00007295}
7296
7297/************************************************************************
7298 * *
7299 * The Parser *
7300 * *
7301 ************************************************************************/
7302
7303/*
William M. Brack08171912003-12-29 02:52:11 +00007304 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007305 * implementation.
7306 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007307static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007308static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007309static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007310static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007311static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7312 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007313
7314/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007315 * xmlXPathCurrentChar:
7316 * @ctxt: the XPath parser context
7317 * @cur: pointer to the beginning of the char
7318 * @len: pointer to the length of the char read
7319 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007320 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007321 * bytes in the input buffer.
7322 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007323 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007324 */
7325
7326static int
7327xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7328 unsigned char c;
7329 unsigned int val;
7330 const xmlChar *cur;
7331
7332 if (ctxt == NULL)
7333 return(0);
7334 cur = ctxt->cur;
7335
7336 /*
7337 * We are supposed to handle UTF8, check it's valid
7338 * From rfc2044: encoding of the Unicode values on UTF-8:
7339 *
7340 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7341 * 0000 0000-0000 007F 0xxxxxxx
7342 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7343 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7344 *
7345 * Check for the 0x110000 limit too
7346 */
7347 c = *cur;
7348 if (c & 0x80) {
7349 if ((cur[1] & 0xc0) != 0x80)
7350 goto encoding_error;
7351 if ((c & 0xe0) == 0xe0) {
7352
7353 if ((cur[2] & 0xc0) != 0x80)
7354 goto encoding_error;
7355 if ((c & 0xf0) == 0xf0) {
7356 if (((c & 0xf8) != 0xf0) ||
7357 ((cur[3] & 0xc0) != 0x80))
7358 goto encoding_error;
7359 /* 4-byte code */
7360 *len = 4;
7361 val = (cur[0] & 0x7) << 18;
7362 val |= (cur[1] & 0x3f) << 12;
7363 val |= (cur[2] & 0x3f) << 6;
7364 val |= cur[3] & 0x3f;
7365 } else {
7366 /* 3-byte code */
7367 *len = 3;
7368 val = (cur[0] & 0xf) << 12;
7369 val |= (cur[1] & 0x3f) << 6;
7370 val |= cur[2] & 0x3f;
7371 }
7372 } else {
7373 /* 2-byte code */
7374 *len = 2;
7375 val = (cur[0] & 0x1f) << 6;
7376 val |= cur[1] & 0x3f;
7377 }
7378 if (!IS_CHAR(val)) {
7379 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7380 }
7381 return(val);
7382 } else {
7383 /* 1-byte code */
7384 *len = 1;
7385 return((int) *cur);
7386 }
7387encoding_error:
7388 /*
William M. Brack08171912003-12-29 02:52:11 +00007389 * If we detect an UTF8 error that probably means that the
7390 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007391 * declaration header. Report the error and switch the encoding
7392 * to ISO-Latin-1 (if you don't like this policy, just declare the
7393 * encoding !)
7394 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007395 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007396 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007397}
7398
7399/**
Owen Taylor3473f882001-02-23 17:55:21 +00007400 * xmlXPathParseNCName:
7401 * @ctxt: the XPath Parser context
7402 *
7403 * parse an XML namespace non qualified name.
7404 *
7405 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7406 *
7407 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7408 * CombiningChar | Extender
7409 *
7410 * Returns the namespace name or NULL
7411 */
7412
7413xmlChar *
7414xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007415 const xmlChar *in;
7416 xmlChar *ret;
7417 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007418
Daniel Veillarda82b1822004-11-08 16:24:57 +00007419 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00007420 /*
7421 * Accelerator for simple ASCII names
7422 */
7423 in = ctxt->cur;
7424 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7425 ((*in >= 0x41) && (*in <= 0x5A)) ||
7426 (*in == '_')) {
7427 in++;
7428 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7429 ((*in >= 0x41) && (*in <= 0x5A)) ||
7430 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007431 (*in == '_') || (*in == '.') ||
7432 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007433 in++;
7434 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7435 (*in == '[') || (*in == ']') || (*in == ':') ||
7436 (*in == '@') || (*in == '*')) {
7437 count = in - ctxt->cur;
7438 if (count == 0)
7439 return(NULL);
7440 ret = xmlStrndup(ctxt->cur, count);
7441 ctxt->cur = in;
7442 return(ret);
7443 }
7444 }
7445 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007446}
7447
Daniel Veillard2156a562001-04-28 12:24:34 +00007448
Owen Taylor3473f882001-02-23 17:55:21 +00007449/**
7450 * xmlXPathParseQName:
7451 * @ctxt: the XPath Parser context
7452 * @prefix: a xmlChar **
7453 *
7454 * parse an XML qualified name
7455 *
7456 * [NS 5] QName ::= (Prefix ':')? LocalPart
7457 *
7458 * [NS 6] Prefix ::= NCName
7459 *
7460 * [NS 7] LocalPart ::= NCName
7461 *
7462 * Returns the function returns the local part, and prefix is updated
7463 * to get the Prefix if any.
7464 */
7465
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007466static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007467xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7468 xmlChar *ret = NULL;
7469
7470 *prefix = NULL;
7471 ret = xmlXPathParseNCName(ctxt);
7472 if (CUR == ':') {
7473 *prefix = ret;
7474 NEXT;
7475 ret = xmlXPathParseNCName(ctxt);
7476 }
7477 return(ret);
7478}
7479
7480/**
7481 * xmlXPathParseName:
7482 * @ctxt: the XPath Parser context
7483 *
7484 * parse an XML name
7485 *
7486 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7487 * CombiningChar | Extender
7488 *
7489 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7490 *
7491 * Returns the namespace name or NULL
7492 */
7493
7494xmlChar *
7495xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007496 const xmlChar *in;
7497 xmlChar *ret;
7498 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007499
Daniel Veillarda82b1822004-11-08 16:24:57 +00007500 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007501 /*
7502 * Accelerator for simple ASCII names
7503 */
7504 in = ctxt->cur;
7505 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7506 ((*in >= 0x41) && (*in <= 0x5A)) ||
7507 (*in == '_') || (*in == ':')) {
7508 in++;
7509 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7510 ((*in >= 0x41) && (*in <= 0x5A)) ||
7511 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007512 (*in == '_') || (*in == '-') ||
7513 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007514 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007515 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007516 count = in - ctxt->cur;
7517 ret = xmlStrndup(ctxt->cur, count);
7518 ctxt->cur = in;
7519 return(ret);
7520 }
7521 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007522 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007523}
7524
Daniel Veillard61d80a22001-04-27 17:13:01 +00007525static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007526xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007527 xmlChar buf[XML_MAX_NAMELEN + 5];
7528 int len = 0, l;
7529 int c;
7530
7531 /*
7532 * Handler for more complex cases
7533 */
7534 c = CUR_CHAR(l);
7535 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007536 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7537 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007538 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007539 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007540 return(NULL);
7541 }
7542
7543 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7544 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7545 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007546 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007547 (IS_COMBINING(c)) ||
7548 (IS_EXTENDER(c)))) {
7549 COPY_BUF(l,buf,len,c);
7550 NEXTL(l);
7551 c = CUR_CHAR(l);
7552 if (len >= XML_MAX_NAMELEN) {
7553 /*
7554 * Okay someone managed to make a huge name, so he's ready to pay
7555 * for the processing speed.
7556 */
7557 xmlChar *buffer;
7558 int max = len * 2;
7559
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007560 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007561 if (buffer == NULL) {
7562 XP_ERROR0(XPATH_MEMORY_ERROR);
7563 }
7564 memcpy(buffer, buf, len);
7565 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7566 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007567 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007568 (IS_COMBINING(c)) ||
7569 (IS_EXTENDER(c))) {
7570 if (len + 10 > max) {
7571 max *= 2;
7572 buffer = (xmlChar *) xmlRealloc(buffer,
7573 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007574 if (buffer == NULL) {
7575 XP_ERROR0(XPATH_MEMORY_ERROR);
7576 }
7577 }
7578 COPY_BUF(l,buffer,len,c);
7579 NEXTL(l);
7580 c = CUR_CHAR(l);
7581 }
7582 buffer[len] = 0;
7583 return(buffer);
7584 }
7585 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007586 if (len == 0)
7587 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007588 return(xmlStrndup(buf, len));
7589}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007590
7591#define MAX_FRAC 20
7592
William M. Brack372a4452004-02-17 13:09:23 +00007593/*
7594 * These are used as divisors for the fractional part of a number.
7595 * Since the table includes 1.0 (representing '0' fractional digits),
7596 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
7597 */
7598static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007599 1.0, 10.0, 100.0, 1000.0, 10000.0,
7600 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7601 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7602 100000000000000.0,
7603 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00007604 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00007605};
7606
Owen Taylor3473f882001-02-23 17:55:21 +00007607/**
7608 * xmlXPathStringEvalNumber:
7609 * @str: A string to scan
7610 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007611 * [30a] Float ::= Number ('e' Digits?)?
7612 *
Owen Taylor3473f882001-02-23 17:55:21 +00007613 * [30] Number ::= Digits ('.' Digits?)?
7614 * | '.' Digits
7615 * [31] Digits ::= [0-9]+
7616 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007617 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007618 * In complement of the Number expression, this function also handles
7619 * negative values : '-' Number.
7620 *
7621 * Returns the double value.
7622 */
7623double
7624xmlXPathStringEvalNumber(const xmlChar *str) {
7625 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007626 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007627 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007628 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007629 int exponent = 0;
7630 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007631#ifdef __GNUC__
7632 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007633 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007634#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007635 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007636 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007637 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7638 return(xmlXPathNAN);
7639 }
7640 if (*cur == '-') {
7641 isneg = 1;
7642 cur++;
7643 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007644
7645#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007646 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007647 * tmp/temp is a workaround against a gcc compiler bug
7648 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007649 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007650 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007651 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007652 ret = ret * 10;
7653 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007654 ok = 1;
7655 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007656 temp = (double) tmp;
7657 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007658 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007659#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007660 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007661 while ((*cur >= '0') && (*cur <= '9')) {
7662 ret = ret * 10 + (*cur - '0');
7663 ok = 1;
7664 cur++;
7665 }
7666#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007667
Owen Taylor3473f882001-02-23 17:55:21 +00007668 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007669 int v, frac = 0;
7670 double fraction = 0;
7671
Owen Taylor3473f882001-02-23 17:55:21 +00007672 cur++;
7673 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7674 return(xmlXPathNAN);
7675 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007676 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7677 v = (*cur - '0');
7678 fraction = fraction * 10 + v;
7679 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007680 cur++;
7681 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007682 fraction /= my_pow10[frac];
7683 ret = ret + fraction;
7684 while ((*cur >= '0') && (*cur <= '9'))
7685 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007686 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007687 if ((*cur == 'e') || (*cur == 'E')) {
7688 cur++;
7689 if (*cur == '-') {
7690 is_exponent_negative = 1;
7691 cur++;
William M. Brack99127052004-05-24 02:52:28 +00007692 } else if (*cur == '+') {
7693 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007694 }
7695 while ((*cur >= '0') && (*cur <= '9')) {
7696 exponent = exponent * 10 + (*cur - '0');
7697 cur++;
7698 }
7699 }
William M. Brack76e95df2003-10-18 16:20:14 +00007700 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007701 if (*cur != 0) return(xmlXPathNAN);
7702 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007703 if (is_exponent_negative) exponent = -exponent;
7704 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007705 return(ret);
7706}
7707
7708/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007709 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007710 * @ctxt: the XPath Parser context
7711 *
7712 * [30] Number ::= Digits ('.' Digits?)?
7713 * | '.' Digits
7714 * [31] Digits ::= [0-9]+
7715 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007716 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007717 *
7718 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007719static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007720xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7721{
Owen Taylor3473f882001-02-23 17:55:21 +00007722 double ret = 0.0;
7723 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007724 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007725 int exponent = 0;
7726 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007727#ifdef __GNUC__
7728 unsigned long tmp = 0;
7729 double temp;
7730#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007731
7732 CHECK_ERROR;
7733 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7734 XP_ERROR(XPATH_NUMBER_ERROR);
7735 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007736#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007737 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007738 * tmp/temp is a workaround against a gcc compiler bug
7739 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007740 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007741 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007742 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007743 ret = ret * 10;
7744 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007745 ok = 1;
7746 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007747 temp = (double) tmp;
7748 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007749 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007750#else
7751 ret = 0;
7752 while ((CUR >= '0') && (CUR <= '9')) {
7753 ret = ret * 10 + (CUR - '0');
7754 ok = 1;
7755 NEXT;
7756 }
7757#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007758 if (CUR == '.') {
7759 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007760 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7761 XP_ERROR(XPATH_NUMBER_ERROR);
7762 }
7763 while ((CUR >= '0') && (CUR <= '9')) {
7764 mult /= 10;
7765 ret = ret + (CUR - '0') * mult;
7766 NEXT;
7767 }
Owen Taylor3473f882001-02-23 17:55:21 +00007768 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007769 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007770 NEXT;
7771 if (CUR == '-') {
7772 is_exponent_negative = 1;
7773 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00007774 } else if (CUR == '+') {
7775 NEXT;
7776 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007777 while ((CUR >= '0') && (CUR <= '9')) {
7778 exponent = exponent * 10 + (CUR - '0');
7779 NEXT;
7780 }
7781 if (is_exponent_negative)
7782 exponent = -exponent;
7783 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007784 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007785 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007786 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007787}
7788
7789/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007790 * xmlXPathParseLiteral:
7791 * @ctxt: the XPath Parser context
7792 *
7793 * Parse a Literal
7794 *
7795 * [29] Literal ::= '"' [^"]* '"'
7796 * | "'" [^']* "'"
7797 *
7798 * Returns the value found or NULL in case of error
7799 */
7800static xmlChar *
7801xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7802 const xmlChar *q;
7803 xmlChar *ret = NULL;
7804
7805 if (CUR == '"') {
7806 NEXT;
7807 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007808 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007809 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007810 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007811 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7812 } else {
7813 ret = xmlStrndup(q, CUR_PTR - q);
7814 NEXT;
7815 }
7816 } else if (CUR == '\'') {
7817 NEXT;
7818 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007819 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007820 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007821 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007822 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7823 } else {
7824 ret = xmlStrndup(q, CUR_PTR - q);
7825 NEXT;
7826 }
7827 } else {
7828 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7829 }
7830 return(ret);
7831}
7832
7833/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007834 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007835 * @ctxt: the XPath Parser context
7836 *
7837 * Parse a Literal and push it on the stack.
7838 *
7839 * [29] Literal ::= '"' [^"]* '"'
7840 * | "'" [^']* "'"
7841 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007842 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007843 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007844static void
7845xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007846 const xmlChar *q;
7847 xmlChar *ret = NULL;
7848
7849 if (CUR == '"') {
7850 NEXT;
7851 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007852 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007853 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007854 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007855 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7856 } else {
7857 ret = xmlStrndup(q, CUR_PTR - q);
7858 NEXT;
7859 }
7860 } else if (CUR == '\'') {
7861 NEXT;
7862 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007863 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007864 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007865 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007866 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7867 } else {
7868 ret = xmlStrndup(q, CUR_PTR - q);
7869 NEXT;
7870 }
7871 } else {
7872 XP_ERROR(XPATH_START_LITERAL_ERROR);
7873 }
7874 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007875 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7876 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007877 xmlFree(ret);
7878}
7879
7880/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007881 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007882 * @ctxt: the XPath Parser context
7883 *
7884 * Parse a VariableReference, evaluate it and push it on the stack.
7885 *
7886 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00007887 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00007888 * of any of the types that are possible for the value of an expression,
7889 * and may also be of additional types not specified here.
7890 *
7891 * Early evaluation is possible since:
7892 * The variable bindings [...] used to evaluate a subexpression are
7893 * always the same as those used to evaluate the containing expression.
7894 *
7895 * [36] VariableReference ::= '$' QName
7896 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007897static void
7898xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007899 xmlChar *name;
7900 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007901
7902 SKIP_BLANKS;
7903 if (CUR != '$') {
7904 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7905 }
7906 NEXT;
7907 name = xmlXPathParseQName(ctxt, &prefix);
7908 if (name == NULL) {
7909 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7910 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007911 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007912 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7913 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007914 SKIP_BLANKS;
7915}
7916
7917/**
7918 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007919 * @name: a name string
7920 *
7921 * Is the name given a NodeType one.
7922 *
7923 * [38] NodeType ::= 'comment'
7924 * | 'text'
7925 * | 'processing-instruction'
7926 * | 'node'
7927 *
7928 * Returns 1 if true 0 otherwise
7929 */
7930int
7931xmlXPathIsNodeType(const xmlChar *name) {
7932 if (name == NULL)
7933 return(0);
7934
Daniel Veillard1971ee22002-01-31 20:29:19 +00007935 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007936 return(1);
7937 if (xmlStrEqual(name, BAD_CAST "text"))
7938 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007939 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007940 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007941 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007942 return(1);
7943 return(0);
7944}
7945
7946/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007947 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007948 * @ctxt: the XPath Parser context
7949 *
7950 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7951 * [17] Argument ::= Expr
7952 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007953 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007954 * pushed on the stack
7955 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007956static void
7957xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007958 xmlChar *name;
7959 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007960 int nbargs = 0;
7961
7962 name = xmlXPathParseQName(ctxt, &prefix);
7963 if (name == NULL) {
7964 XP_ERROR(XPATH_EXPR_ERROR);
7965 }
7966 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007967#ifdef DEBUG_EXPR
7968 if (prefix == NULL)
7969 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7970 name);
7971 else
7972 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7973 prefix, name);
7974#endif
7975
Owen Taylor3473f882001-02-23 17:55:21 +00007976 if (CUR != '(') {
7977 XP_ERROR(XPATH_EXPR_ERROR);
7978 }
7979 NEXT;
7980 SKIP_BLANKS;
7981
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007982 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007983 if (CUR != ')') {
7984 while (CUR != 0) {
7985 int op1 = ctxt->comp->last;
7986 ctxt->comp->last = -1;
7987 xmlXPathCompileExpr(ctxt);
7988 CHECK_ERROR;
7989 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7990 nbargs++;
7991 if (CUR == ')') break;
7992 if (CUR != ',') {
7993 XP_ERROR(XPATH_EXPR_ERROR);
7994 }
7995 NEXT;
7996 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007997 }
Owen Taylor3473f882001-02-23 17:55:21 +00007998 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007999 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
8000 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00008001 NEXT;
8002 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00008003}
8004
8005/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008006 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008007 * @ctxt: the XPath Parser context
8008 *
8009 * [15] PrimaryExpr ::= VariableReference
8010 * | '(' Expr ')'
8011 * | Literal
8012 * | Number
8013 * | FunctionCall
8014 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008015 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008016 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008017static void
8018xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008019 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008020 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008021 else if (CUR == '(') {
8022 NEXT;
8023 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008024 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00008025 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00008026 if (CUR != ')') {
8027 XP_ERROR(XPATH_EXPR_ERROR);
8028 }
8029 NEXT;
8030 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008031 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008032 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008033 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008034 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008035 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008036 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008037 }
8038 SKIP_BLANKS;
8039}
8040
8041/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008042 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008043 * @ctxt: the XPath Parser context
8044 *
8045 * [20] FilterExpr ::= PrimaryExpr
8046 * | FilterExpr Predicate
8047 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008048 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008049 * Square brackets are used to filter expressions in the same way that
8050 * they are used in location paths. It is an error if the expression to
8051 * be filtered does not evaluate to a node-set. The context node list
8052 * used for evaluating the expression in square brackets is the node-set
8053 * to be filtered listed in document order.
8054 */
8055
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008056static void
8057xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8058 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008059 CHECK_ERROR;
8060 SKIP_BLANKS;
8061
8062 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008063 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00008064 SKIP_BLANKS;
8065 }
8066
8067
8068}
8069
8070/**
8071 * xmlXPathScanName:
8072 * @ctxt: the XPath Parser context
8073 *
8074 * Trickery: parse an XML name but without consuming the input flow
8075 * Needed to avoid insanity in the parser state.
8076 *
8077 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8078 * CombiningChar | Extender
8079 *
8080 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8081 *
8082 * [6] Names ::= Name (S Name)*
8083 *
8084 * Returns the Name parsed or NULL
8085 */
8086
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008087static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00008088xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +00008089 int len = 0, l;
8090 int c;
Daniel Veillard03226812004-11-01 14:55:21 +00008091 const xmlChar *cur;
8092 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00008093
Daniel Veillard03226812004-11-01 14:55:21 +00008094 cur = ctxt->cur;
8095
8096 c = CUR_CHAR(l);
8097 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8098 (!IS_LETTER(c) && (c != '_') &&
8099 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008100 return(NULL);
8101 }
8102
Daniel Veillard03226812004-11-01 14:55:21 +00008103 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8104 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8105 (c == '.') || (c == '-') ||
8106 (c == '_') || (c == ':') ||
8107 (IS_COMBINING(c)) ||
8108 (IS_EXTENDER(c)))) {
8109 len += l;
8110 NEXTL(l);
8111 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +00008112 }
Daniel Veillard03226812004-11-01 14:55:21 +00008113 ret = xmlStrndup(cur, ctxt->cur - cur);
8114 ctxt->cur = cur;
8115 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00008116}
8117
8118/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008119 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008120 * @ctxt: the XPath Parser context
8121 *
8122 * [19] PathExpr ::= LocationPath
8123 * | FilterExpr
8124 * | FilterExpr '/' RelativeLocationPath
8125 * | FilterExpr '//' RelativeLocationPath
8126 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008127 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008128 * The / operator and // operators combine an arbitrary expression
8129 * and a relative location path. It is an error if the expression
8130 * does not evaluate to a node-set.
8131 * The / operator does composition in the same way as when / is
8132 * used in a location path. As in location paths, // is short for
8133 * /descendant-or-self::node()/.
8134 */
8135
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008136static void
8137xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008138 int lc = 1; /* Should we branch to LocationPath ? */
8139 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8140
8141 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008142 if ((CUR == '$') || (CUR == '(') ||
8143 (IS_ASCII_DIGIT(CUR)) ||
8144 (CUR == '\'') || (CUR == '"') ||
8145 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008146 lc = 0;
8147 } else if (CUR == '*') {
8148 /* relative or absolute location path */
8149 lc = 1;
8150 } else if (CUR == '/') {
8151 /* relative or absolute location path */
8152 lc = 1;
8153 } else if (CUR == '@') {
8154 /* relative abbreviated attribute location path */
8155 lc = 1;
8156 } else if (CUR == '.') {
8157 /* relative abbreviated attribute location path */
8158 lc = 1;
8159 } else {
8160 /*
8161 * Problem is finding if we have a name here whether it's:
8162 * - a nodetype
8163 * - a function call in which case it's followed by '('
8164 * - an axis in which case it's followed by ':'
8165 * - a element name
8166 * We do an a priori analysis here rather than having to
8167 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008168 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008169 * read/write/debug.
8170 */
8171 SKIP_BLANKS;
8172 name = xmlXPathScanName(ctxt);
8173 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8174#ifdef DEBUG_STEP
8175 xmlGenericError(xmlGenericErrorContext,
8176 "PathExpr: Axis\n");
8177#endif
8178 lc = 1;
8179 xmlFree(name);
8180 } else if (name != NULL) {
8181 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008182
8183
8184 while (NXT(len) != 0) {
8185 if (NXT(len) == '/') {
8186 /* element name */
8187#ifdef DEBUG_STEP
8188 xmlGenericError(xmlGenericErrorContext,
8189 "PathExpr: AbbrRelLocation\n");
8190#endif
8191 lc = 1;
8192 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008193 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008194 /* ignore blanks */
8195 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008196 } else if (NXT(len) == ':') {
8197#ifdef DEBUG_STEP
8198 xmlGenericError(xmlGenericErrorContext,
8199 "PathExpr: AbbrRelLocation\n");
8200#endif
8201 lc = 1;
8202 break;
8203 } else if ((NXT(len) == '(')) {
8204 /* Note Type or Function */
8205 if (xmlXPathIsNodeType(name)) {
8206#ifdef DEBUG_STEP
8207 xmlGenericError(xmlGenericErrorContext,
8208 "PathExpr: Type search\n");
8209#endif
8210 lc = 1;
8211 } else {
8212#ifdef DEBUG_STEP
8213 xmlGenericError(xmlGenericErrorContext,
8214 "PathExpr: function call\n");
8215#endif
8216 lc = 0;
8217 }
8218 break;
8219 } else if ((NXT(len) == '[')) {
8220 /* element name */
8221#ifdef DEBUG_STEP
8222 xmlGenericError(xmlGenericErrorContext,
8223 "PathExpr: AbbrRelLocation\n");
8224#endif
8225 lc = 1;
8226 break;
8227 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8228 (NXT(len) == '=')) {
8229 lc = 1;
8230 break;
8231 } else {
8232 lc = 1;
8233 break;
8234 }
8235 len++;
8236 }
8237 if (NXT(len) == 0) {
8238#ifdef DEBUG_STEP
8239 xmlGenericError(xmlGenericErrorContext,
8240 "PathExpr: AbbrRelLocation\n");
8241#endif
8242 /* element name */
8243 lc = 1;
8244 }
8245 xmlFree(name);
8246 } else {
William M. Brack08171912003-12-29 02:52:11 +00008247 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008248 XP_ERROR(XPATH_EXPR_ERROR);
8249 }
8250 }
8251
8252 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008253 if (CUR == '/') {
8254 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8255 } else {
8256 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008257 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008258 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008259 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008260 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008261 CHECK_ERROR;
8262 if ((CUR == '/') && (NXT(1) == '/')) {
8263 SKIP(2);
8264 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008265
8266 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8267 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8268 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8269
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008270 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008271 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008272 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008273 }
8274 }
8275 SKIP_BLANKS;
8276}
8277
8278/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008279 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008280 * @ctxt: the XPath Parser context
8281 *
8282 * [18] UnionExpr ::= PathExpr
8283 * | UnionExpr '|' PathExpr
8284 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008285 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008286 */
8287
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008288static void
8289xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8290 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008291 CHECK_ERROR;
8292 SKIP_BLANKS;
8293 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008294 int op1 = ctxt->comp->last;
8295 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008296
8297 NEXT;
8298 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008299 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008300
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008301 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8302
Owen Taylor3473f882001-02-23 17:55:21 +00008303 SKIP_BLANKS;
8304 }
Owen Taylor3473f882001-02-23 17:55:21 +00008305}
8306
8307/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008308 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008309 * @ctxt: the XPath Parser context
8310 *
8311 * [27] UnaryExpr ::= UnionExpr
8312 * | '-' UnaryExpr
8313 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008314 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008315 */
8316
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008317static void
8318xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008319 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008320 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008321
8322 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008323 while (CUR == '-') {
8324 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008325 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008326 NEXT;
8327 SKIP_BLANKS;
8328 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008329
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008330 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008331 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008332 if (found) {
8333 if (minus)
8334 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8335 else
8336 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008337 }
8338}
8339
8340/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008341 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008342 * @ctxt: the XPath Parser context
8343 *
8344 * [26] MultiplicativeExpr ::= UnaryExpr
8345 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8346 * | MultiplicativeExpr 'div' UnaryExpr
8347 * | MultiplicativeExpr 'mod' UnaryExpr
8348 * [34] MultiplyOperator ::= '*'
8349 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008350 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008351 */
8352
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008353static void
8354xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8355 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008356 CHECK_ERROR;
8357 SKIP_BLANKS;
8358 while ((CUR == '*') ||
8359 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8360 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8361 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008362 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008363
8364 if (CUR == '*') {
8365 op = 0;
8366 NEXT;
8367 } else if (CUR == 'd') {
8368 op = 1;
8369 SKIP(3);
8370 } else if (CUR == 'm') {
8371 op = 2;
8372 SKIP(3);
8373 }
8374 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008375 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008376 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008377 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008378 SKIP_BLANKS;
8379 }
8380}
8381
8382/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008383 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008384 * @ctxt: the XPath Parser context
8385 *
8386 * [25] AdditiveExpr ::= MultiplicativeExpr
8387 * | AdditiveExpr '+' MultiplicativeExpr
8388 * | AdditiveExpr '-' MultiplicativeExpr
8389 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008390 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008391 */
8392
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008393static void
8394xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008395
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008396 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008397 CHECK_ERROR;
8398 SKIP_BLANKS;
8399 while ((CUR == '+') || (CUR == '-')) {
8400 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008401 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008402
8403 if (CUR == '+') plus = 1;
8404 else plus = 0;
8405 NEXT;
8406 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008407 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008408 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008409 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008410 SKIP_BLANKS;
8411 }
8412}
8413
8414/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008415 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008416 * @ctxt: the XPath Parser context
8417 *
8418 * [24] RelationalExpr ::= AdditiveExpr
8419 * | RelationalExpr '<' AdditiveExpr
8420 * | RelationalExpr '>' AdditiveExpr
8421 * | RelationalExpr '<=' AdditiveExpr
8422 * | RelationalExpr '>=' AdditiveExpr
8423 *
8424 * A <= B > C is allowed ? Answer from James, yes with
8425 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8426 * which is basically what got implemented.
8427 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008428 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008429 * on the stack
8430 */
8431
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008432static void
8433xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8434 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008435 CHECK_ERROR;
8436 SKIP_BLANKS;
8437 while ((CUR == '<') ||
8438 (CUR == '>') ||
8439 ((CUR == '<') && (NXT(1) == '=')) ||
8440 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008441 int inf, strict;
8442 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008443
8444 if (CUR == '<') inf = 1;
8445 else inf = 0;
8446 if (NXT(1) == '=') strict = 0;
8447 else strict = 1;
8448 NEXT;
8449 if (!strict) NEXT;
8450 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008451 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008452 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008453 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008454 SKIP_BLANKS;
8455 }
8456}
8457
8458/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008459 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008460 * @ctxt: the XPath Parser context
8461 *
8462 * [23] EqualityExpr ::= RelationalExpr
8463 * | EqualityExpr '=' RelationalExpr
8464 * | EqualityExpr '!=' RelationalExpr
8465 *
8466 * A != B != C is allowed ? Answer from James, yes with
8467 * (RelationalExpr = RelationalExpr) = RelationalExpr
8468 * (RelationalExpr != RelationalExpr) != RelationalExpr
8469 * which is basically what got implemented.
8470 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008471 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008472 *
8473 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008474static void
8475xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8476 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008477 CHECK_ERROR;
8478 SKIP_BLANKS;
8479 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008480 int eq;
8481 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008482
8483 if (CUR == '=') eq = 1;
8484 else eq = 0;
8485 NEXT;
8486 if (!eq) NEXT;
8487 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008488 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008489 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008490 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008491 SKIP_BLANKS;
8492 }
8493}
8494
8495/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008496 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008497 * @ctxt: the XPath Parser context
8498 *
8499 * [22] AndExpr ::= EqualityExpr
8500 * | AndExpr 'and' EqualityExpr
8501 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008502 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008503 *
8504 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008505static void
8506xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8507 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008508 CHECK_ERROR;
8509 SKIP_BLANKS;
8510 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008511 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008512 SKIP(3);
8513 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008514 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008515 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008516 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008517 SKIP_BLANKS;
8518 }
8519}
8520
8521/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008522 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008523 * @ctxt: the XPath Parser context
8524 *
8525 * [14] Expr ::= OrExpr
8526 * [21] OrExpr ::= AndExpr
8527 * | OrExpr 'or' AndExpr
8528 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008529 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008530 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008531static void
8532xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8533 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008534 CHECK_ERROR;
8535 SKIP_BLANKS;
8536 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008537 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008538 SKIP(2);
8539 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008540 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008541 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008542 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8543 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008544 SKIP_BLANKS;
8545 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008546 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8547 /* more ops could be optimized too */
8548 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8549 }
Owen Taylor3473f882001-02-23 17:55:21 +00008550}
8551
8552/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008553 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008554 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008555 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008556 *
8557 * [8] Predicate ::= '[' PredicateExpr ']'
8558 * [9] PredicateExpr ::= Expr
8559 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008560 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008561 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008562static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008563xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008564 int op1 = ctxt->comp->last;
8565
8566 SKIP_BLANKS;
8567 if (CUR != '[') {
8568 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8569 }
8570 NEXT;
8571 SKIP_BLANKS;
8572
8573 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008574 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008575 CHECK_ERROR;
8576
8577 if (CUR != ']') {
8578 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8579 }
8580
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008581 if (filter)
8582 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8583 else
8584 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008585
8586 NEXT;
8587 SKIP_BLANKS;
8588}
8589
8590/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008591 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008592 * @ctxt: the XPath Parser context
8593 * @test: pointer to a xmlXPathTestVal
8594 * @type: pointer to a xmlXPathTypeVal
8595 * @prefix: placeholder for a possible name prefix
8596 *
8597 * [7] NodeTest ::= NameTest
8598 * | NodeType '(' ')'
8599 * | 'processing-instruction' '(' Literal ')'
8600 *
8601 * [37] NameTest ::= '*'
8602 * | NCName ':' '*'
8603 * | QName
8604 * [38] NodeType ::= 'comment'
8605 * | 'text'
8606 * | 'processing-instruction'
8607 * | 'node'
8608 *
William M. Brack08171912003-12-29 02:52:11 +00008609 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00008610 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008611static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008612xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8613 xmlXPathTypeVal *type, const xmlChar **prefix,
8614 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008615 int blanks;
8616
8617 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8618 STRANGE;
8619 return(NULL);
8620 }
William M. Brack78637da2003-07-31 14:47:38 +00008621 *type = (xmlXPathTypeVal) 0;
8622 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008623 *prefix = NULL;
8624 SKIP_BLANKS;
8625
8626 if ((name == NULL) && (CUR == '*')) {
8627 /*
8628 * All elements
8629 */
8630 NEXT;
8631 *test = NODE_TEST_ALL;
8632 return(NULL);
8633 }
8634
8635 if (name == NULL)
8636 name = xmlXPathParseNCName(ctxt);
8637 if (name == NULL) {
8638 XP_ERROR0(XPATH_EXPR_ERROR);
8639 }
8640
William M. Brack76e95df2003-10-18 16:20:14 +00008641 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008642 SKIP_BLANKS;
8643 if (CUR == '(') {
8644 NEXT;
8645 /*
8646 * NodeType or PI search
8647 */
8648 if (xmlStrEqual(name, BAD_CAST "comment"))
8649 *type = NODE_TYPE_COMMENT;
8650 else if (xmlStrEqual(name, BAD_CAST "node"))
8651 *type = NODE_TYPE_NODE;
8652 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8653 *type = NODE_TYPE_PI;
8654 else if (xmlStrEqual(name, BAD_CAST "text"))
8655 *type = NODE_TYPE_TEXT;
8656 else {
8657 if (name != NULL)
8658 xmlFree(name);
8659 XP_ERROR0(XPATH_EXPR_ERROR);
8660 }
8661
8662 *test = NODE_TEST_TYPE;
8663
8664 SKIP_BLANKS;
8665 if (*type == NODE_TYPE_PI) {
8666 /*
8667 * Specific case: search a PI by name.
8668 */
Owen Taylor3473f882001-02-23 17:55:21 +00008669 if (name != NULL)
8670 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008671 name = NULL;
8672 if (CUR != ')') {
8673 name = xmlXPathParseLiteral(ctxt);
8674 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008675 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008676 SKIP_BLANKS;
8677 }
Owen Taylor3473f882001-02-23 17:55:21 +00008678 }
8679 if (CUR != ')') {
8680 if (name != NULL)
8681 xmlFree(name);
8682 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8683 }
8684 NEXT;
8685 return(name);
8686 }
8687 *test = NODE_TEST_NAME;
8688 if ((!blanks) && (CUR == ':')) {
8689 NEXT;
8690
8691 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008692 * Since currently the parser context don't have a
8693 * namespace list associated:
8694 * The namespace name for this prefix can be computed
8695 * only at evaluation time. The compilation is done
8696 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008697 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008698#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008699 *prefix = xmlXPathNsLookup(ctxt->context, name);
8700 if (name != NULL)
8701 xmlFree(name);
8702 if (*prefix == NULL) {
8703 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8704 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008705#else
8706 *prefix = name;
8707#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008708
8709 if (CUR == '*') {
8710 /*
8711 * All elements
8712 */
8713 NEXT;
8714 *test = NODE_TEST_ALL;
8715 return(NULL);
8716 }
8717
8718 name = xmlXPathParseNCName(ctxt);
8719 if (name == NULL) {
8720 XP_ERROR0(XPATH_EXPR_ERROR);
8721 }
8722 }
8723 return(name);
8724}
8725
8726/**
8727 * xmlXPathIsAxisName:
8728 * @name: a preparsed name token
8729 *
8730 * [6] AxisName ::= 'ancestor'
8731 * | 'ancestor-or-self'
8732 * | 'attribute'
8733 * | 'child'
8734 * | 'descendant'
8735 * | 'descendant-or-self'
8736 * | 'following'
8737 * | 'following-sibling'
8738 * | 'namespace'
8739 * | 'parent'
8740 * | 'preceding'
8741 * | 'preceding-sibling'
8742 * | 'self'
8743 *
8744 * Returns the axis or 0
8745 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008746static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008747xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008748 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008749 switch (name[0]) {
8750 case 'a':
8751 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8752 ret = AXIS_ANCESTOR;
8753 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8754 ret = AXIS_ANCESTOR_OR_SELF;
8755 if (xmlStrEqual(name, BAD_CAST "attribute"))
8756 ret = AXIS_ATTRIBUTE;
8757 break;
8758 case 'c':
8759 if (xmlStrEqual(name, BAD_CAST "child"))
8760 ret = AXIS_CHILD;
8761 break;
8762 case 'd':
8763 if (xmlStrEqual(name, BAD_CAST "descendant"))
8764 ret = AXIS_DESCENDANT;
8765 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8766 ret = AXIS_DESCENDANT_OR_SELF;
8767 break;
8768 case 'f':
8769 if (xmlStrEqual(name, BAD_CAST "following"))
8770 ret = AXIS_FOLLOWING;
8771 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8772 ret = AXIS_FOLLOWING_SIBLING;
8773 break;
8774 case 'n':
8775 if (xmlStrEqual(name, BAD_CAST "namespace"))
8776 ret = AXIS_NAMESPACE;
8777 break;
8778 case 'p':
8779 if (xmlStrEqual(name, BAD_CAST "parent"))
8780 ret = AXIS_PARENT;
8781 if (xmlStrEqual(name, BAD_CAST "preceding"))
8782 ret = AXIS_PRECEDING;
8783 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8784 ret = AXIS_PRECEDING_SIBLING;
8785 break;
8786 case 's':
8787 if (xmlStrEqual(name, BAD_CAST "self"))
8788 ret = AXIS_SELF;
8789 break;
8790 }
8791 return(ret);
8792}
8793
8794/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008795 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008796 * @ctxt: the XPath Parser context
8797 *
8798 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8799 * | AbbreviatedStep
8800 *
8801 * [12] AbbreviatedStep ::= '.' | '..'
8802 *
8803 * [5] AxisSpecifier ::= AxisName '::'
8804 * | AbbreviatedAxisSpecifier
8805 *
8806 * [13] AbbreviatedAxisSpecifier ::= '@'?
8807 *
8808 * Modified for XPtr range support as:
8809 *
8810 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8811 * | AbbreviatedStep
8812 * | 'range-to' '(' Expr ')' Predicate*
8813 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008814 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008815 * A location step of . is short for self::node(). This is
8816 * particularly useful in conjunction with //. For example, the
8817 * location path .//para is short for
8818 * self::node()/descendant-or-self::node()/child::para
8819 * and so will select all para descendant elements of the context
8820 * node.
8821 * Similarly, a location step of .. is short for parent::node().
8822 * For example, ../title is short for parent::node()/child::title
8823 * and so will select the title children of the parent of the context
8824 * node.
8825 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008826static void
8827xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008828#ifdef LIBXML_XPTR_ENABLED
8829 int rangeto = 0;
8830 int op2 = -1;
8831#endif
8832
Owen Taylor3473f882001-02-23 17:55:21 +00008833 SKIP_BLANKS;
8834 if ((CUR == '.') && (NXT(1) == '.')) {
8835 SKIP(2);
8836 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008837 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8838 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008839 } else if (CUR == '.') {
8840 NEXT;
8841 SKIP_BLANKS;
8842 } else {
8843 xmlChar *name = NULL;
8844 const xmlChar *prefix = NULL;
8845 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008846 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008847 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008848 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008849
8850 /*
8851 * The modification needed for XPointer change to the production
8852 */
8853#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008854 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008855 name = xmlXPathParseNCName(ctxt);
8856 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008857 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008858 xmlFree(name);
8859 SKIP_BLANKS;
8860 if (CUR != '(') {
8861 XP_ERROR(XPATH_EXPR_ERROR);
8862 }
8863 NEXT;
8864 SKIP_BLANKS;
8865
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008866 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008867 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008868 CHECK_ERROR;
8869
8870 SKIP_BLANKS;
8871 if (CUR != ')') {
8872 XP_ERROR(XPATH_EXPR_ERROR);
8873 }
8874 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008875 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008876 goto eval_predicates;
8877 }
8878 }
8879#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008880 if (CUR == '*') {
8881 axis = AXIS_CHILD;
8882 } else {
8883 if (name == NULL)
8884 name = xmlXPathParseNCName(ctxt);
8885 if (name != NULL) {
8886 axis = xmlXPathIsAxisName(name);
8887 if (axis != 0) {
8888 SKIP_BLANKS;
8889 if ((CUR == ':') && (NXT(1) == ':')) {
8890 SKIP(2);
8891 xmlFree(name);
8892 name = NULL;
8893 } else {
8894 /* an element name can conflict with an axis one :-\ */
8895 axis = AXIS_CHILD;
8896 }
Owen Taylor3473f882001-02-23 17:55:21 +00008897 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008898 axis = AXIS_CHILD;
8899 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008900 } else if (CUR == '@') {
8901 NEXT;
8902 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008903 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008904 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008905 }
Owen Taylor3473f882001-02-23 17:55:21 +00008906 }
8907
8908 CHECK_ERROR;
8909
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008910 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008911 if (test == 0)
8912 return;
8913
8914#ifdef DEBUG_STEP
8915 xmlGenericError(xmlGenericErrorContext,
8916 "Basis : computing new set\n");
8917#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008918
Owen Taylor3473f882001-02-23 17:55:21 +00008919#ifdef DEBUG_STEP
8920 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008921 if (ctxt->value == NULL)
8922 xmlGenericError(xmlGenericErrorContext, "no value\n");
8923 else if (ctxt->value->nodesetval == NULL)
8924 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8925 else
8926 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008927#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008928
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008929#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008930eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008931#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008932 op1 = ctxt->comp->last;
8933 ctxt->comp->last = -1;
8934
Owen Taylor3473f882001-02-23 17:55:21 +00008935 SKIP_BLANKS;
8936 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008937 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008938 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008939
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008940#ifdef LIBXML_XPTR_ENABLED
8941 if (rangeto) {
8942 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8943 } else
8944#endif
8945 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8946 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008947
Owen Taylor3473f882001-02-23 17:55:21 +00008948 }
8949#ifdef DEBUG_STEP
8950 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008951 if (ctxt->value == NULL)
8952 xmlGenericError(xmlGenericErrorContext, "no value\n");
8953 else if (ctxt->value->nodesetval == NULL)
8954 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8955 else
8956 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8957 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008958#endif
8959}
8960
8961/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008962 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008963 * @ctxt: the XPath Parser context
8964 *
8965 * [3] RelativeLocationPath ::= Step
8966 * | RelativeLocationPath '/' Step
8967 * | AbbreviatedRelativeLocationPath
8968 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8969 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008970 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008971 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008972static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008973xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008974(xmlXPathParserContextPtr ctxt) {
8975 SKIP_BLANKS;
8976 if ((CUR == '/') && (NXT(1) == '/')) {
8977 SKIP(2);
8978 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008979 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8980 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008981 } else if (CUR == '/') {
8982 NEXT;
8983 SKIP_BLANKS;
8984 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008985 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008986 SKIP_BLANKS;
8987 while (CUR == '/') {
8988 if ((CUR == '/') && (NXT(1) == '/')) {
8989 SKIP(2);
8990 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008991 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008992 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008993 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008994 } else if (CUR == '/') {
8995 NEXT;
8996 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008997 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008998 }
8999 SKIP_BLANKS;
9000 }
9001}
9002
9003/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009004 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00009005 * @ctxt: the XPath Parser context
9006 *
9007 * [1] LocationPath ::= RelativeLocationPath
9008 * | AbsoluteLocationPath
9009 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
9010 * | AbbreviatedAbsoluteLocationPath
9011 * [10] AbbreviatedAbsoluteLocationPath ::=
9012 * '//' RelativeLocationPath
9013 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009014 * Compile a location path
9015 *
Owen Taylor3473f882001-02-23 17:55:21 +00009016 * // is short for /descendant-or-self::node()/. For example,
9017 * //para is short for /descendant-or-self::node()/child::para and
9018 * so will select any para element in the document (even a para element
9019 * that is a document element will be selected by //para since the
9020 * document element node is a child of the root node); div//para is
9021 * short for div/descendant-or-self::node()/child::para and so will
9022 * select all para descendants of div children.
9023 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009024static void
9025xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009026 SKIP_BLANKS;
9027 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009028 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009029 } else {
9030 while (CUR == '/') {
9031 if ((CUR == '/') && (NXT(1) == '/')) {
9032 SKIP(2);
9033 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009034 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9035 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009036 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009037 } else if (CUR == '/') {
9038 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00009039 SKIP_BLANKS;
9040 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +00009041 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00009042 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009043 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009044 }
9045 }
9046 }
9047}
9048
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009049/************************************************************************
9050 * *
9051 * XPath precompiled expression evaluation *
9052 * *
9053 ************************************************************************/
9054
Daniel Veillardf06307e2001-07-03 10:35:50 +00009055static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009056xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
9057
9058/**
9059 * xmlXPathNodeCollectAndTest:
9060 * @ctxt: the XPath Parser context
9061 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009062 * @first: pointer to the first element in document order
9063 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009064 *
9065 * This is the function implementing a step: based on the current list
9066 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009067 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009068 *
9069 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00009070 *
William M. Brack08171912003-12-29 02:52:11 +00009071 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009072 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009073static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009074xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009075 xmlXPathStepOpPtr op,
9076 xmlNodePtr * first, xmlNodePtr * last)
9077{
William M. Brack78637da2003-07-31 14:47:38 +00009078 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9079 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9080 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009081 const xmlChar *prefix = op->value4;
9082 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009083 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009084
9085#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009086 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009087#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009088 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009089 xmlNodeSetPtr ret, list;
9090 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009091 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00009092 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009093 xmlNodePtr cur = NULL;
9094 xmlXPathObjectPtr obj;
9095 xmlNodeSetPtr nodelist;
9096 xmlNodePtr tmp;
9097
Daniel Veillardf06307e2001-07-03 10:35:50 +00009098 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009099 obj = valuePop(ctxt);
9100 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009101 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009102 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009103 URI = xmlXPathNsLookup(ctxt->context, prefix);
9104 if (URI == NULL)
9105 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00009106 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009107#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009108 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009109#endif
9110 switch (axis) {
9111 case AXIS_ANCESTOR:
9112#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009113 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009114#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009115 first = NULL;
9116 next = xmlXPathNextAncestor;
9117 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009118 case AXIS_ANCESTOR_OR_SELF:
9119#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009120 xmlGenericError(xmlGenericErrorContext,
9121 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009122#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009123 first = NULL;
9124 next = xmlXPathNextAncestorOrSelf;
9125 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009126 case AXIS_ATTRIBUTE:
9127#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009128 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009129#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009130 first = NULL;
9131 last = NULL;
9132 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009133 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009134 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009135 case AXIS_CHILD:
9136#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009137 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009138#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009139 last = NULL;
9140 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009141 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009142 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009143 case AXIS_DESCENDANT:
9144#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009145 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009146#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009147 last = NULL;
9148 next = xmlXPathNextDescendant;
9149 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009150 case AXIS_DESCENDANT_OR_SELF:
9151#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009152 xmlGenericError(xmlGenericErrorContext,
9153 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009154#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009155 last = NULL;
9156 next = xmlXPathNextDescendantOrSelf;
9157 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009158 case AXIS_FOLLOWING:
9159#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009160 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009161#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009162 last = NULL;
9163 next = xmlXPathNextFollowing;
9164 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009165 case AXIS_FOLLOWING_SIBLING:
9166#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009167 xmlGenericError(xmlGenericErrorContext,
9168 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009169#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009170 last = NULL;
9171 next = xmlXPathNextFollowingSibling;
9172 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009173 case AXIS_NAMESPACE:
9174#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009175 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009176#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009177 first = NULL;
9178 last = NULL;
9179 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009180 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009181 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009182 case AXIS_PARENT:
9183#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009184 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009185#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009186 first = NULL;
9187 next = xmlXPathNextParent;
9188 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009189 case AXIS_PRECEDING:
9190#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009191 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009192#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009193 first = NULL;
9194 next = xmlXPathNextPrecedingInternal;
9195 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009196 case AXIS_PRECEDING_SIBLING:
9197#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009198 xmlGenericError(xmlGenericErrorContext,
9199 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009200#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009201 first = NULL;
9202 next = xmlXPathNextPrecedingSibling;
9203 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009204 case AXIS_SELF:
9205#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009206 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009207#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009208 first = NULL;
9209 last = NULL;
9210 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009211 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009212 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009213 }
9214 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009215 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009216
9217 nodelist = obj->nodesetval;
9218 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009219 xmlXPathFreeObject(obj);
9220 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9221 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009222 }
9223 addNode = xmlXPathNodeSetAddUnique;
9224 ret = NULL;
9225#ifdef DEBUG_STEP
9226 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009227 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009228 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009229 case NODE_TEST_NONE:
9230 xmlGenericError(xmlGenericErrorContext,
9231 " searching for none !!!\n");
9232 break;
9233 case NODE_TEST_TYPE:
9234 xmlGenericError(xmlGenericErrorContext,
9235 " searching for type %d\n", type);
9236 break;
9237 case NODE_TEST_PI:
9238 xmlGenericError(xmlGenericErrorContext,
9239 " searching for PI !!!\n");
9240 break;
9241 case NODE_TEST_ALL:
9242 xmlGenericError(xmlGenericErrorContext,
9243 " searching for *\n");
9244 break;
9245 case NODE_TEST_NS:
9246 xmlGenericError(xmlGenericErrorContext,
9247 " searching for namespace %s\n",
9248 prefix);
9249 break;
9250 case NODE_TEST_NAME:
9251 xmlGenericError(xmlGenericErrorContext,
9252 " searching for name %s\n", name);
9253 if (prefix != NULL)
9254 xmlGenericError(xmlGenericErrorContext,
9255 " with namespace %s\n", prefix);
9256 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009257 }
9258 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9259#endif
9260 /*
9261 * 2.3 Node Tests
9262 * - For the attribute axis, the principal node type is attribute.
9263 * - For the namespace axis, the principal node type is namespace.
9264 * - For other axes, the principal node type is element.
9265 *
9266 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009267 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009268 * select all element children of the context node
9269 */
9270 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009271 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009272 ctxt->context->node = nodelist->nodeTab[i];
9273
Daniel Veillardf06307e2001-07-03 10:35:50 +00009274 cur = NULL;
9275 list = xmlXPathNodeSetCreate(NULL);
9276 do {
9277 cur = next(ctxt, cur);
9278 if (cur == NULL)
9279 break;
9280 if ((first != NULL) && (*first == cur))
9281 break;
9282 if (((t % 256) == 0) &&
9283 (first != NULL) && (*first != NULL) &&
9284 (xmlXPathCmpNodes(*first, cur) >= 0))
9285 break;
9286 if ((last != NULL) && (*last == cur))
9287 break;
9288 if (((t % 256) == 0) &&
9289 (last != NULL) && (*last != NULL) &&
9290 (xmlXPathCmpNodes(cur, *last) >= 0))
9291 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009292 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009293#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009294 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9295#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009296 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009297 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009298 ctxt->context->node = tmp;
9299 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009300 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009301 if ((cur->type == type) ||
9302 ((type == NODE_TYPE_NODE) &&
9303 ((cur->type == XML_DOCUMENT_NODE) ||
9304 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9305 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009306 (cur->type == XML_NAMESPACE_DECL) ||
9307 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009308 (cur->type == XML_PI_NODE) ||
9309 (cur->type == XML_COMMENT_NODE) ||
9310 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009311 (cur->type == XML_TEXT_NODE))) ||
9312 ((type == NODE_TYPE_TEXT) &&
9313 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009314#ifdef DEBUG_STEP
9315 n++;
9316#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009317 addNode(list, cur);
9318 }
9319 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009320 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009321 if (cur->type == XML_PI_NODE) {
9322 if ((name != NULL) &&
9323 (!xmlStrEqual(name, cur->name)))
9324 break;
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 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009331 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009332 if (axis == AXIS_ATTRIBUTE) {
9333 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009334#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009335 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009336#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009337 addNode(list, cur);
9338 }
9339 } else if (axis == AXIS_NAMESPACE) {
9340 if (cur->type == XML_NAMESPACE_DECL) {
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 Veillard044fc6b2002-03-04 17:09:44 +00009344 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9345 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009346 }
9347 } else {
9348 if (cur->type == XML_ELEMENT_NODE) {
9349 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009350#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009351 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009352#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009353 addNode(list, cur);
9354 } else if ((cur->ns != NULL) &&
9355 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009356#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009357 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009358#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009359 addNode(list, cur);
9360 }
9361 }
9362 }
9363 break;
9364 case NODE_TEST_NS:{
9365 TODO;
9366 break;
9367 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009368 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009369 switch (cur->type) {
9370 case XML_ELEMENT_NODE:
9371 if (xmlStrEqual(name, cur->name)) {
9372 if (prefix == NULL) {
9373 if (cur->ns == NULL) {
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 } else {
9380 if ((cur->ns != NULL) &&
9381 (xmlStrEqual(URI,
9382 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009383#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009384 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009385#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009386 addNode(list, cur);
9387 }
9388 }
9389 }
9390 break;
9391 case XML_ATTRIBUTE_NODE:{
9392 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009393
Daniel Veillardf06307e2001-07-03 10:35:50 +00009394 if (xmlStrEqual(name, attr->name)) {
9395 if (prefix == NULL) {
9396 if ((attr->ns == NULL) ||
9397 (attr->ns->prefix == NULL)) {
9398#ifdef DEBUG_STEP
9399 n++;
9400#endif
9401 addNode(list,
9402 (xmlNodePtr) attr);
9403 }
9404 } else {
9405 if ((attr->ns != NULL) &&
9406 (xmlStrEqual(URI,
9407 attr->ns->
9408 href))) {
9409#ifdef DEBUG_STEP
9410 n++;
9411#endif
9412 addNode(list,
9413 (xmlNodePtr) attr);
9414 }
9415 }
9416 }
9417 break;
9418 }
9419 case XML_NAMESPACE_DECL:
9420 if (cur->type == XML_NAMESPACE_DECL) {
9421 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009422
Daniel Veillardf06307e2001-07-03 10:35:50 +00009423 if ((ns->prefix != NULL) && (name != NULL)
9424 && (xmlStrEqual(ns->prefix, name))) {
9425#ifdef DEBUG_STEP
9426 n++;
9427#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009428 xmlXPathNodeSetAddNs(list,
9429 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009430 }
9431 }
9432 break;
9433 default:
9434 break;
9435 }
9436 break;
9437 break;
9438 }
9439 } while (cur != NULL);
9440
9441 /*
9442 * If there is some predicate filtering do it now
9443 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009444 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009445 xmlXPathObjectPtr obj2;
9446
9447 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9448 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9449 CHECK_TYPE0(XPATH_NODESET);
9450 obj2 = valuePop(ctxt);
9451 list = obj2->nodesetval;
9452 obj2->nodesetval = NULL;
9453 xmlXPathFreeObject(obj2);
9454 }
9455 if (ret == NULL) {
9456 ret = list;
9457 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009458 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009459 xmlXPathFreeNodeSet(list);
9460 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009461 }
9462 ctxt->context->node = tmp;
9463#ifdef DEBUG_STEP
9464 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009465 "\nExamined %d nodes, found %d nodes at that step\n",
9466 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009467#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009468 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009469 if ((obj->boolval) && (obj->user != NULL)) {
9470 ctxt->value->boolval = 1;
9471 ctxt->value->user = obj->user;
9472 obj->user = NULL;
9473 obj->boolval = 0;
9474 }
9475 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009476 return(t);
9477}
9478
9479/**
9480 * xmlXPathNodeCollectAndTestNth:
9481 * @ctxt: the XPath Parser context
9482 * @op: the XPath precompiled step operation
9483 * @indx: the index to collect
9484 * @first: pointer to the first element in document order
9485 * @last: pointer to the last element in document order
9486 *
9487 * This is the function implementing a step: based on the current list
9488 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009489 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009490 *
9491 * Pushes the new NodeSet resulting from the search.
9492 * Returns the number of node traversed
9493 */
9494static int
9495xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9496 xmlXPathStepOpPtr op, int indx,
9497 xmlNodePtr * first, xmlNodePtr * last)
9498{
William M. Brack78637da2003-07-31 14:47:38 +00009499 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9500 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9501 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009502 const xmlChar *prefix = op->value4;
9503 const xmlChar *name = op->value5;
9504 const xmlChar *URI = NULL;
9505 int n = 0, t = 0;
9506
9507 int i;
9508 xmlNodeSetPtr list;
9509 xmlXPathTraversalFunction next = NULL;
9510 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9511 xmlNodePtr cur = NULL;
9512 xmlXPathObjectPtr obj;
9513 xmlNodeSetPtr nodelist;
9514 xmlNodePtr tmp;
9515
9516 CHECK_TYPE0(XPATH_NODESET);
9517 obj = valuePop(ctxt);
9518 addNode = xmlXPathNodeSetAdd;
9519 if (prefix != NULL) {
9520 URI = xmlXPathNsLookup(ctxt->context, prefix);
9521 if (URI == NULL)
9522 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9523 }
9524#ifdef DEBUG_STEP_NTH
9525 xmlGenericError(xmlGenericErrorContext, "new step : ");
9526 if (first != NULL) {
9527 if (*first != NULL)
9528 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9529 (*first)->name);
9530 else
9531 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9532 }
9533 if (last != NULL) {
9534 if (*last != NULL)
9535 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9536 (*last)->name);
9537 else
9538 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9539 }
9540#endif
9541 switch (axis) {
9542 case AXIS_ANCESTOR:
9543#ifdef DEBUG_STEP_NTH
9544 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9545#endif
9546 first = NULL;
9547 next = xmlXPathNextAncestor;
9548 break;
9549 case AXIS_ANCESTOR_OR_SELF:
9550#ifdef DEBUG_STEP_NTH
9551 xmlGenericError(xmlGenericErrorContext,
9552 "axis 'ancestors-or-self' ");
9553#endif
9554 first = NULL;
9555 next = xmlXPathNextAncestorOrSelf;
9556 break;
9557 case AXIS_ATTRIBUTE:
9558#ifdef DEBUG_STEP_NTH
9559 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9560#endif
9561 first = NULL;
9562 last = NULL;
9563 next = xmlXPathNextAttribute;
9564 break;
9565 case AXIS_CHILD:
9566#ifdef DEBUG_STEP_NTH
9567 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9568#endif
9569 last = NULL;
9570 next = xmlXPathNextChild;
9571 break;
9572 case AXIS_DESCENDANT:
9573#ifdef DEBUG_STEP_NTH
9574 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9575#endif
9576 last = NULL;
9577 next = xmlXPathNextDescendant;
9578 break;
9579 case AXIS_DESCENDANT_OR_SELF:
9580#ifdef DEBUG_STEP_NTH
9581 xmlGenericError(xmlGenericErrorContext,
9582 "axis 'descendant-or-self' ");
9583#endif
9584 last = NULL;
9585 next = xmlXPathNextDescendantOrSelf;
9586 break;
9587 case AXIS_FOLLOWING:
9588#ifdef DEBUG_STEP_NTH
9589 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9590#endif
9591 last = NULL;
9592 next = xmlXPathNextFollowing;
9593 break;
9594 case AXIS_FOLLOWING_SIBLING:
9595#ifdef DEBUG_STEP_NTH
9596 xmlGenericError(xmlGenericErrorContext,
9597 "axis 'following-siblings' ");
9598#endif
9599 last = NULL;
9600 next = xmlXPathNextFollowingSibling;
9601 break;
9602 case AXIS_NAMESPACE:
9603#ifdef DEBUG_STEP_NTH
9604 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9605#endif
9606 last = NULL;
9607 first = NULL;
9608 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9609 break;
9610 case AXIS_PARENT:
9611#ifdef DEBUG_STEP_NTH
9612 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9613#endif
9614 first = NULL;
9615 next = xmlXPathNextParent;
9616 break;
9617 case AXIS_PRECEDING:
9618#ifdef DEBUG_STEP_NTH
9619 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9620#endif
9621 first = NULL;
9622 next = xmlXPathNextPrecedingInternal;
9623 break;
9624 case AXIS_PRECEDING_SIBLING:
9625#ifdef DEBUG_STEP_NTH
9626 xmlGenericError(xmlGenericErrorContext,
9627 "axis 'preceding-sibling' ");
9628#endif
9629 first = NULL;
9630 next = xmlXPathNextPrecedingSibling;
9631 break;
9632 case AXIS_SELF:
9633#ifdef DEBUG_STEP_NTH
9634 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9635#endif
9636 first = NULL;
9637 last = NULL;
9638 next = xmlXPathNextSelf;
9639 break;
9640 }
9641 if (next == NULL)
9642 return(0);
9643
9644 nodelist = obj->nodesetval;
9645 if (nodelist == NULL) {
9646 xmlXPathFreeObject(obj);
9647 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9648 return(0);
9649 }
9650 addNode = xmlXPathNodeSetAddUnique;
9651#ifdef DEBUG_STEP_NTH
9652 xmlGenericError(xmlGenericErrorContext,
9653 " context contains %d nodes\n", nodelist->nodeNr);
9654 switch (test) {
9655 case NODE_TEST_NONE:
9656 xmlGenericError(xmlGenericErrorContext,
9657 " searching for none !!!\n");
9658 break;
9659 case NODE_TEST_TYPE:
9660 xmlGenericError(xmlGenericErrorContext,
9661 " searching for type %d\n", type);
9662 break;
9663 case NODE_TEST_PI:
9664 xmlGenericError(xmlGenericErrorContext,
9665 " searching for PI !!!\n");
9666 break;
9667 case NODE_TEST_ALL:
9668 xmlGenericError(xmlGenericErrorContext,
9669 " searching for *\n");
9670 break;
9671 case NODE_TEST_NS:
9672 xmlGenericError(xmlGenericErrorContext,
9673 " searching for namespace %s\n",
9674 prefix);
9675 break;
9676 case NODE_TEST_NAME:
9677 xmlGenericError(xmlGenericErrorContext,
9678 " searching for name %s\n", name);
9679 if (prefix != NULL)
9680 xmlGenericError(xmlGenericErrorContext,
9681 " with namespace %s\n", prefix);
9682 break;
9683 }
9684 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9685#endif
9686 /*
9687 * 2.3 Node Tests
9688 * - For the attribute axis, the principal node type is attribute.
9689 * - For the namespace axis, the principal node type is namespace.
9690 * - For other axes, the principal node type is element.
9691 *
9692 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009693 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009694 * select all element children of the context node
9695 */
9696 tmp = ctxt->context->node;
9697 list = xmlXPathNodeSetCreate(NULL);
9698 for (i = 0; i < nodelist->nodeNr; i++) {
9699 ctxt->context->node = nodelist->nodeTab[i];
9700
9701 cur = NULL;
9702 n = 0;
9703 do {
9704 cur = next(ctxt, cur);
9705 if (cur == NULL)
9706 break;
9707 if ((first != NULL) && (*first == cur))
9708 break;
9709 if (((t % 256) == 0) &&
9710 (first != NULL) && (*first != NULL) &&
9711 (xmlXPathCmpNodes(*first, cur) >= 0))
9712 break;
9713 if ((last != NULL) && (*last == cur))
9714 break;
9715 if (((t % 256) == 0) &&
9716 (last != NULL) && (*last != NULL) &&
9717 (xmlXPathCmpNodes(cur, *last) >= 0))
9718 break;
9719 t++;
9720 switch (test) {
9721 case NODE_TEST_NONE:
9722 ctxt->context->node = tmp;
9723 STRANGE return(0);
9724 case NODE_TEST_TYPE:
9725 if ((cur->type == type) ||
9726 ((type == NODE_TYPE_NODE) &&
9727 ((cur->type == XML_DOCUMENT_NODE) ||
9728 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9729 (cur->type == XML_ELEMENT_NODE) ||
9730 (cur->type == XML_PI_NODE) ||
9731 (cur->type == XML_COMMENT_NODE) ||
9732 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009733 (cur->type == XML_TEXT_NODE))) ||
9734 ((type == NODE_TYPE_TEXT) &&
9735 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009736 n++;
9737 if (n == indx)
9738 addNode(list, cur);
9739 }
9740 break;
9741 case NODE_TEST_PI:
9742 if (cur->type == XML_PI_NODE) {
9743 if ((name != NULL) &&
9744 (!xmlStrEqual(name, cur->name)))
9745 break;
9746 n++;
9747 if (n == indx)
9748 addNode(list, cur);
9749 }
9750 break;
9751 case NODE_TEST_ALL:
9752 if (axis == AXIS_ATTRIBUTE) {
9753 if (cur->type == XML_ATTRIBUTE_NODE) {
9754 n++;
9755 if (n == indx)
9756 addNode(list, cur);
9757 }
9758 } else if (axis == AXIS_NAMESPACE) {
9759 if (cur->type == XML_NAMESPACE_DECL) {
9760 n++;
9761 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009762 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9763 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009764 }
9765 } else {
9766 if (cur->type == XML_ELEMENT_NODE) {
9767 if (prefix == NULL) {
9768 n++;
9769 if (n == indx)
9770 addNode(list, cur);
9771 } else if ((cur->ns != NULL) &&
9772 (xmlStrEqual(URI, cur->ns->href))) {
9773 n++;
9774 if (n == indx)
9775 addNode(list, cur);
9776 }
9777 }
9778 }
9779 break;
9780 case NODE_TEST_NS:{
9781 TODO;
9782 break;
9783 }
9784 case NODE_TEST_NAME:
9785 switch (cur->type) {
9786 case XML_ELEMENT_NODE:
9787 if (xmlStrEqual(name, cur->name)) {
9788 if (prefix == NULL) {
9789 if (cur->ns == NULL) {
9790 n++;
9791 if (n == indx)
9792 addNode(list, cur);
9793 }
9794 } else {
9795 if ((cur->ns != NULL) &&
9796 (xmlStrEqual(URI,
9797 cur->ns->href))) {
9798 n++;
9799 if (n == indx)
9800 addNode(list, cur);
9801 }
9802 }
9803 }
9804 break;
9805 case XML_ATTRIBUTE_NODE:{
9806 xmlAttrPtr attr = (xmlAttrPtr) cur;
9807
9808 if (xmlStrEqual(name, attr->name)) {
9809 if (prefix == NULL) {
9810 if ((attr->ns == NULL) ||
9811 (attr->ns->prefix == NULL)) {
9812 n++;
9813 if (n == indx)
9814 addNode(list, cur);
9815 }
9816 } else {
9817 if ((attr->ns != NULL) &&
9818 (xmlStrEqual(URI,
9819 attr->ns->
9820 href))) {
9821 n++;
9822 if (n == indx)
9823 addNode(list, cur);
9824 }
9825 }
9826 }
9827 break;
9828 }
9829 case XML_NAMESPACE_DECL:
9830 if (cur->type == XML_NAMESPACE_DECL) {
9831 xmlNsPtr ns = (xmlNsPtr) cur;
9832
9833 if ((ns->prefix != NULL) && (name != NULL)
9834 && (xmlStrEqual(ns->prefix, name))) {
9835 n++;
9836 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009837 xmlXPathNodeSetAddNs(list,
9838 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009839 }
9840 }
9841 break;
9842 default:
9843 break;
9844 }
9845 break;
9846 break;
9847 }
9848 } while (n < indx);
9849 }
9850 ctxt->context->node = tmp;
9851#ifdef DEBUG_STEP_NTH
9852 xmlGenericError(xmlGenericErrorContext,
9853 "\nExamined %d nodes, found %d nodes at that step\n",
9854 t, list->nodeNr);
9855#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009856 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009857 if ((obj->boolval) && (obj->user != NULL)) {
9858 ctxt->value->boolval = 1;
9859 ctxt->value->user = obj->user;
9860 obj->user = NULL;
9861 obj->boolval = 0;
9862 }
9863 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009864 return(t);
9865}
9866
9867/**
9868 * xmlXPathCompOpEvalFirst:
9869 * @ctxt: the XPath parser context with the compiled expression
9870 * @op: an XPath compiled operation
9871 * @first: the first elem found so far
9872 *
9873 * Evaluate the Precompiled XPath operation searching only the first
9874 * element in document order
9875 *
9876 * Returns the number of examined objects.
9877 */
9878static int
9879xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9880 xmlXPathStepOpPtr op, xmlNodePtr * first)
9881{
9882 int total = 0, cur;
9883 xmlXPathCompExprPtr comp;
9884 xmlXPathObjectPtr arg1, arg2;
9885
Daniel Veillard556c6682001-10-06 09:59:51 +00009886 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009887 comp = ctxt->comp;
9888 switch (op->op) {
9889 case XPATH_OP_END:
9890 return (0);
9891 case XPATH_OP_UNION:
9892 total =
9893 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9894 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009895 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009896 if ((ctxt->value != NULL)
9897 && (ctxt->value->type == XPATH_NODESET)
9898 && (ctxt->value->nodesetval != NULL)
9899 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9900 /*
9901 * limit tree traversing to first node in the result
9902 */
9903 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9904 *first = ctxt->value->nodesetval->nodeTab[0];
9905 }
9906 cur =
9907 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9908 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009909 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009910 CHECK_TYPE0(XPATH_NODESET);
9911 arg2 = valuePop(ctxt);
9912
9913 CHECK_TYPE0(XPATH_NODESET);
9914 arg1 = valuePop(ctxt);
9915
9916 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9917 arg2->nodesetval);
9918 valuePush(ctxt, arg1);
9919 xmlXPathFreeObject(arg2);
9920 /* optimizer */
9921 if (total > cur)
9922 xmlXPathCompSwap(op);
9923 return (total + cur);
9924 case XPATH_OP_ROOT:
9925 xmlXPathRoot(ctxt);
9926 return (0);
9927 case XPATH_OP_NODE:
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 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9935 return (total);
9936 case XPATH_OP_RESET:
9937 if (op->ch1 != -1)
9938 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009939 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009940 if (op->ch2 != -1)
9941 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009942 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009943 ctxt->context->node = NULL;
9944 return (total);
9945 case XPATH_OP_COLLECT:{
9946 if (op->ch1 == -1)
9947 return (total);
9948
9949 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009950 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009951
9952 /*
9953 * Optimization for [n] selection where n is a number
9954 */
9955 if ((op->ch2 != -1) &&
9956 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9957 (comp->steps[op->ch2].ch1 == -1) &&
9958 (comp->steps[op->ch2].ch2 != -1) &&
9959 (comp->steps[comp->steps[op->ch2].ch2].op ==
9960 XPATH_OP_VALUE)) {
9961 xmlXPathObjectPtr val;
9962
9963 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9964 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9965 int indx = (int) val->floatval;
9966
9967 if (val->floatval == (float) indx) {
9968 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9969 first, NULL);
9970 return (total);
9971 }
9972 }
9973 }
9974 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9975 return (total);
9976 }
9977 case XPATH_OP_VALUE:
9978 valuePush(ctxt,
9979 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9980 return (0);
9981 case XPATH_OP_SORT:
9982 if (op->ch1 != -1)
9983 total +=
9984 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9985 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009986 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009987 if ((ctxt->value != NULL)
9988 && (ctxt->value->type == XPATH_NODESET)
9989 && (ctxt->value->nodesetval != NULL))
9990 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9991 return (total);
9992 default:
9993 return (xmlXPathCompOpEval(ctxt, op));
9994 }
9995}
9996
9997/**
9998 * xmlXPathCompOpEvalLast:
9999 * @ctxt: the XPath parser context with the compiled expression
10000 * @op: an XPath compiled operation
10001 * @last: the last elem found so far
10002 *
10003 * Evaluate the Precompiled XPath operation searching only the last
10004 * element in document order
10005 *
William M. Brack08171912003-12-29 02:52:11 +000010006 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000010007 */
10008static int
10009xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
10010 xmlNodePtr * last)
10011{
10012 int total = 0, cur;
10013 xmlXPathCompExprPtr comp;
10014 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000010015 xmlNodePtr bak;
10016 xmlDocPtr bakd;
10017 int pp;
10018 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010019
Daniel Veillard556c6682001-10-06 09:59:51 +000010020 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010021 comp = ctxt->comp;
10022 switch (op->op) {
10023 case XPATH_OP_END:
10024 return (0);
10025 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000010026 bakd = ctxt->context->doc;
10027 bak = ctxt->context->node;
10028 pp = ctxt->context->proximityPosition;
10029 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010030 total =
10031 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010032 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010033 if ((ctxt->value != NULL)
10034 && (ctxt->value->type == XPATH_NODESET)
10035 && (ctxt->value->nodesetval != NULL)
10036 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10037 /*
10038 * limit tree traversing to first node in the result
10039 */
10040 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10041 *last =
10042 ctxt->value->nodesetval->nodeTab[ctxt->value->
10043 nodesetval->nodeNr -
10044 1];
10045 }
William M. Brackce4fc562004-01-22 02:47:18 +000010046 ctxt->context->doc = bakd;
10047 ctxt->context->node = bak;
10048 ctxt->context->proximityPosition = pp;
10049 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010050 cur =
10051 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010052 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010053 if ((ctxt->value != NULL)
10054 && (ctxt->value->type == XPATH_NODESET)
10055 && (ctxt->value->nodesetval != NULL)
10056 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10057 }
10058 CHECK_TYPE0(XPATH_NODESET);
10059 arg2 = valuePop(ctxt);
10060
10061 CHECK_TYPE0(XPATH_NODESET);
10062 arg1 = valuePop(ctxt);
10063
10064 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10065 arg2->nodesetval);
10066 valuePush(ctxt, arg1);
10067 xmlXPathFreeObject(arg2);
10068 /* optimizer */
10069 if (total > cur)
10070 xmlXPathCompSwap(op);
10071 return (total + cur);
10072 case XPATH_OP_ROOT:
10073 xmlXPathRoot(ctxt);
10074 return (0);
10075 case XPATH_OP_NODE:
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 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10083 return (total);
10084 case XPATH_OP_RESET:
10085 if (op->ch1 != -1)
10086 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010087 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010088 if (op->ch2 != -1)
10089 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010090 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010091 ctxt->context->node = NULL;
10092 return (total);
10093 case XPATH_OP_COLLECT:{
10094 if (op->ch1 == -1)
10095 return (0);
10096
10097 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010098 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010099
10100 /*
10101 * Optimization for [n] selection where n is a number
10102 */
10103 if ((op->ch2 != -1) &&
10104 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10105 (comp->steps[op->ch2].ch1 == -1) &&
10106 (comp->steps[op->ch2].ch2 != -1) &&
10107 (comp->steps[comp->steps[op->ch2].ch2].op ==
10108 XPATH_OP_VALUE)) {
10109 xmlXPathObjectPtr val;
10110
10111 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10112 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10113 int indx = (int) val->floatval;
10114
10115 if (val->floatval == (float) indx) {
10116 total +=
10117 xmlXPathNodeCollectAndTestNth(ctxt, op,
10118 indx, NULL,
10119 last);
10120 return (total);
10121 }
10122 }
10123 }
10124 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10125 return (total);
10126 }
10127 case XPATH_OP_VALUE:
10128 valuePush(ctxt,
10129 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10130 return (0);
10131 case XPATH_OP_SORT:
10132 if (op->ch1 != -1)
10133 total +=
10134 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10135 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010136 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010137 if ((ctxt->value != NULL)
10138 && (ctxt->value->type == XPATH_NODESET)
10139 && (ctxt->value->nodesetval != NULL))
10140 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10141 return (total);
10142 default:
10143 return (xmlXPathCompOpEval(ctxt, op));
10144 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010145}
10146
Owen Taylor3473f882001-02-23 17:55:21 +000010147/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010148 * xmlXPathCompOpEval:
10149 * @ctxt: the XPath parser context with the compiled expression
10150 * @op: an XPath compiled operation
10151 *
10152 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010153 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010154 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010155static int
10156xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10157{
10158 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010159 int equal, ret;
10160 xmlXPathCompExprPtr comp;
10161 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010162 xmlNodePtr bak;
10163 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010164 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010165 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010166
Daniel Veillard556c6682001-10-06 09:59:51 +000010167 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010168 comp = ctxt->comp;
10169 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010170 case XPATH_OP_END:
10171 return (0);
10172 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010173 bakd = ctxt->context->doc;
10174 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010175 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010176 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010177 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010178 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010179 xmlXPathBooleanFunction(ctxt, 1);
10180 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10181 return (total);
10182 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010183 ctxt->context->doc = bakd;
10184 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010185 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010186 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010187 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010188 if (ctxt->error) {
10189 xmlXPathFreeObject(arg2);
10190 return(0);
10191 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010192 xmlXPathBooleanFunction(ctxt, 1);
10193 arg1 = valuePop(ctxt);
10194 arg1->boolval &= arg2->boolval;
10195 valuePush(ctxt, arg1);
10196 xmlXPathFreeObject(arg2);
10197 return (total);
10198 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010199 bakd = ctxt->context->doc;
10200 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010201 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010202 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010203 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010204 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010205 xmlXPathBooleanFunction(ctxt, 1);
10206 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10207 return (total);
10208 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010209 ctxt->context->doc = bakd;
10210 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010211 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010212 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010213 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010214 if (ctxt->error) {
10215 xmlXPathFreeObject(arg2);
10216 return(0);
10217 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010218 xmlXPathBooleanFunction(ctxt, 1);
10219 arg1 = valuePop(ctxt);
10220 arg1->boolval |= arg2->boolval;
10221 valuePush(ctxt, arg1);
10222 xmlXPathFreeObject(arg2);
10223 return (total);
10224 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010225 bakd = ctxt->context->doc;
10226 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010227 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010228 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010229 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010230 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010231 ctxt->context->doc = bakd;
10232 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010233 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010234 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010235 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010236 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010237 if (op->value)
10238 equal = xmlXPathEqualValues(ctxt);
10239 else
10240 equal = xmlXPathNotEqualValues(ctxt);
10241 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010242 return (total);
10243 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010244 bakd = ctxt->context->doc;
10245 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010246 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010247 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010248 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010249 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010250 ctxt->context->doc = bakd;
10251 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010252 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010253 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010254 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010255 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010256 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10257 valuePush(ctxt, xmlXPathNewBoolean(ret));
10258 return (total);
10259 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010260 bakd = ctxt->context->doc;
10261 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010262 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010263 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010264 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010265 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010266 if (op->ch2 != -1) {
10267 ctxt->context->doc = bakd;
10268 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010269 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010270 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010271 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010272 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010273 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010274 if (op->value == 0)
10275 xmlXPathSubValues(ctxt);
10276 else if (op->value == 1)
10277 xmlXPathAddValues(ctxt);
10278 else if (op->value == 2)
10279 xmlXPathValueFlipSign(ctxt);
10280 else if (op->value == 3) {
10281 CAST_TO_NUMBER;
10282 CHECK_TYPE0(XPATH_NUMBER);
10283 }
10284 return (total);
10285 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010286 bakd = ctxt->context->doc;
10287 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010288 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010289 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010290 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010291 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010292 ctxt->context->doc = bakd;
10293 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010294 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010295 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010296 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010297 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010298 if (op->value == 0)
10299 xmlXPathMultValues(ctxt);
10300 else if (op->value == 1)
10301 xmlXPathDivValues(ctxt);
10302 else if (op->value == 2)
10303 xmlXPathModValues(ctxt);
10304 return (total);
10305 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010306 bakd = ctxt->context->doc;
10307 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010308 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010309 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010310 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010311 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010312 ctxt->context->doc = bakd;
10313 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010314 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010315 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010316 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010317 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010318 CHECK_TYPE0(XPATH_NODESET);
10319 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010320
Daniel Veillardf06307e2001-07-03 10:35:50 +000010321 CHECK_TYPE0(XPATH_NODESET);
10322 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010323
Daniel Veillardf06307e2001-07-03 10:35:50 +000010324 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10325 arg2->nodesetval);
10326 valuePush(ctxt, arg1);
10327 xmlXPathFreeObject(arg2);
10328 return (total);
10329 case XPATH_OP_ROOT:
10330 xmlXPathRoot(ctxt);
10331 return (total);
10332 case XPATH_OP_NODE:
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 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10340 return (total);
10341 case XPATH_OP_RESET:
10342 if (op->ch1 != -1)
10343 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010344 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010345 if (op->ch2 != -1)
10346 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010347 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010348 ctxt->context->node = NULL;
10349 return (total);
10350 case XPATH_OP_COLLECT:{
10351 if (op->ch1 == -1)
10352 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010353
Daniel Veillardf06307e2001-07-03 10:35:50 +000010354 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010355 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010356
Daniel Veillardf06307e2001-07-03 10:35:50 +000010357 /*
10358 * Optimization for [n] selection where n is a number
10359 */
10360 if ((op->ch2 != -1) &&
10361 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10362 (comp->steps[op->ch2].ch1 == -1) &&
10363 (comp->steps[op->ch2].ch2 != -1) &&
10364 (comp->steps[comp->steps[op->ch2].ch2].op ==
10365 XPATH_OP_VALUE)) {
10366 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010367
Daniel Veillardf06307e2001-07-03 10:35:50 +000010368 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10369 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10370 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010371
Daniel Veillardf06307e2001-07-03 10:35:50 +000010372 if (val->floatval == (float) indx) {
10373 total +=
10374 xmlXPathNodeCollectAndTestNth(ctxt, op,
10375 indx, NULL,
10376 NULL);
10377 return (total);
10378 }
10379 }
10380 }
10381 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10382 return (total);
10383 }
10384 case XPATH_OP_VALUE:
10385 valuePush(ctxt,
10386 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10387 return (total);
10388 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010389 xmlXPathObjectPtr val;
10390
Daniel Veillardf06307e2001-07-03 10:35:50 +000010391 if (op->ch1 != -1)
10392 total +=
10393 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010394 if (op->value5 == NULL) {
10395 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10396 if (val == NULL) {
10397 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10398 return(0);
10399 }
10400 valuePush(ctxt, val);
10401 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010402 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010403
Daniel Veillardf06307e2001-07-03 10:35:50 +000010404 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10405 if (URI == NULL) {
10406 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010407 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010408 op->value4, op->value5);
10409 return (total);
10410 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010411 val = xmlXPathVariableLookupNS(ctxt->context,
10412 op->value4, URI);
10413 if (val == NULL) {
10414 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10415 return(0);
10416 }
10417 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010418 }
10419 return (total);
10420 }
10421 case XPATH_OP_FUNCTION:{
10422 xmlXPathFunction func;
10423 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010424 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010425
10426 if (op->ch1 != -1)
10427 total +=
10428 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010429 if (ctxt->valueNr < op->value) {
10430 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010431 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010432 ctxt->error = XPATH_INVALID_OPERAND;
10433 return (total);
10434 }
10435 for (i = 0; i < op->value; i++)
10436 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10437 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010438 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010439 ctxt->error = XPATH_INVALID_OPERAND;
10440 return (total);
10441 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010442 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000010443 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010444 else {
10445 const xmlChar *URI = NULL;
10446
10447 if (op->value5 == NULL)
10448 func =
10449 xmlXPathFunctionLookup(ctxt->context,
10450 op->value4);
10451 else {
10452 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10453 if (URI == NULL) {
10454 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010455 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010456 op->value4, op->value5);
10457 return (total);
10458 }
10459 func = xmlXPathFunctionLookupNS(ctxt->context,
10460 op->value4, URI);
10461 }
10462 if (func == NULL) {
10463 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010464 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010465 op->value4);
10466 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010467 }
William M. Brackad0e67c2004-12-01 14:35:10 +000010468 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010469 op->cacheURI = (void *) URI;
10470 }
10471 oldFunc = ctxt->context->function;
10472 oldFuncURI = ctxt->context->functionURI;
10473 ctxt->context->function = op->value4;
10474 ctxt->context->functionURI = op->cacheURI;
10475 func(ctxt, op->value);
10476 ctxt->context->function = oldFunc;
10477 ctxt->context->functionURI = oldFuncURI;
10478 return (total);
10479 }
10480 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010481 bakd = ctxt->context->doc;
10482 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000010483 pp = ctxt->context->proximityPosition;
10484 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010485 if (op->ch1 != -1)
10486 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000010487 ctxt->context->contextSize = cs;
10488 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000010489 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000010490 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000010491 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010492 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010493 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010494 ctxt->context->doc = bakd;
10495 ctxt->context->node = bak;
10496 CHECK_ERROR0;
10497 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010498 return (total);
10499 case XPATH_OP_PREDICATE:
10500 case XPATH_OP_FILTER:{
10501 xmlXPathObjectPtr res;
10502 xmlXPathObjectPtr obj, tmp;
10503 xmlNodeSetPtr newset = NULL;
10504 xmlNodeSetPtr oldset;
10505 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000010506 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010507 int i;
10508
10509 /*
10510 * Optimization for ()[1] selection i.e. the first elem
10511 */
10512 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10513 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10514 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10515 xmlXPathObjectPtr val;
10516
10517 val = comp->steps[op->ch2].value4;
10518 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10519 (val->floatval == 1.0)) {
10520 xmlNodePtr first = NULL;
10521
10522 total +=
10523 xmlXPathCompOpEvalFirst(ctxt,
10524 &comp->steps[op->ch1],
10525 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010526 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010527 /*
10528 * The nodeset should be in document order,
10529 * Keep only the first value
10530 */
10531 if ((ctxt->value != NULL) &&
10532 (ctxt->value->type == XPATH_NODESET) &&
10533 (ctxt->value->nodesetval != NULL) &&
10534 (ctxt->value->nodesetval->nodeNr > 1))
10535 ctxt->value->nodesetval->nodeNr = 1;
10536 return (total);
10537 }
10538 }
10539 /*
10540 * Optimization for ()[last()] selection i.e. the last elem
10541 */
10542 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10543 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10544 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10545 int f = comp->steps[op->ch2].ch1;
10546
10547 if ((f != -1) &&
10548 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10549 (comp->steps[f].value5 == NULL) &&
10550 (comp->steps[f].value == 0) &&
10551 (comp->steps[f].value4 != NULL) &&
10552 (xmlStrEqual
10553 (comp->steps[f].value4, BAD_CAST "last"))) {
10554 xmlNodePtr last = NULL;
10555
10556 total +=
10557 xmlXPathCompOpEvalLast(ctxt,
10558 &comp->steps[op->ch1],
10559 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010560 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010561 /*
10562 * The nodeset should be in document order,
10563 * Keep only the last value
10564 */
10565 if ((ctxt->value != NULL) &&
10566 (ctxt->value->type == XPATH_NODESET) &&
10567 (ctxt->value->nodesetval != NULL) &&
10568 (ctxt->value->nodesetval->nodeTab != NULL) &&
10569 (ctxt->value->nodesetval->nodeNr > 1)) {
10570 ctxt->value->nodesetval->nodeTab[0] =
10571 ctxt->value->nodesetval->nodeTab[ctxt->
10572 value->
10573 nodesetval->
10574 nodeNr -
10575 1];
10576 ctxt->value->nodesetval->nodeNr = 1;
10577 }
10578 return (total);
10579 }
10580 }
10581
10582 if (op->ch1 != -1)
10583 total +=
10584 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010585 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010586 if (op->ch2 == -1)
10587 return (total);
10588 if (ctxt->value == NULL)
10589 return (total);
10590
10591 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010592
10593#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010594 /*
10595 * Hum are we filtering the result of an XPointer expression
10596 */
10597 if (ctxt->value->type == XPATH_LOCATIONSET) {
10598 xmlLocationSetPtr newlocset = NULL;
10599 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010600
Daniel Veillardf06307e2001-07-03 10:35:50 +000010601 /*
10602 * Extract the old locset, and then evaluate the result of the
10603 * expression for all the element in the locset. use it to grow
10604 * up a new locset.
10605 */
10606 CHECK_TYPE0(XPATH_LOCATIONSET);
10607 obj = valuePop(ctxt);
10608 oldlocset = obj->user;
10609 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010610
Daniel Veillardf06307e2001-07-03 10:35:50 +000010611 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10612 ctxt->context->contextSize = 0;
10613 ctxt->context->proximityPosition = 0;
10614 if (op->ch2 != -1)
10615 total +=
10616 xmlXPathCompOpEval(ctxt,
10617 &comp->steps[op->ch2]);
10618 res = valuePop(ctxt);
10619 if (res != NULL)
10620 xmlXPathFreeObject(res);
10621 valuePush(ctxt, obj);
10622 CHECK_ERROR0;
10623 return (total);
10624 }
10625 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010626
Daniel Veillardf06307e2001-07-03 10:35:50 +000010627 for (i = 0; i < oldlocset->locNr; i++) {
10628 /*
10629 * Run the evaluation with a node list made of a
10630 * single item in the nodelocset.
10631 */
10632 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010633 ctxt->context->contextSize = oldlocset->locNr;
10634 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010635 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10636 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010637
Daniel Veillardf06307e2001-07-03 10:35:50 +000010638 if (op->ch2 != -1)
10639 total +=
10640 xmlXPathCompOpEval(ctxt,
10641 &comp->steps[op->ch2]);
10642 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010643
Daniel Veillardf06307e2001-07-03 10:35:50 +000010644 /*
10645 * The result of the evaluation need to be tested to
10646 * decided whether the filter succeeded or not
10647 */
10648 res = valuePop(ctxt);
10649 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10650 xmlXPtrLocationSetAdd(newlocset,
10651 xmlXPathObjectCopy
10652 (oldlocset->locTab[i]));
10653 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010654
Daniel Veillardf06307e2001-07-03 10:35:50 +000010655 /*
10656 * Cleanup
10657 */
10658 if (res != NULL)
10659 xmlXPathFreeObject(res);
10660 if (ctxt->value == tmp) {
10661 res = valuePop(ctxt);
10662 xmlXPathFreeObject(res);
10663 }
10664
10665 ctxt->context->node = NULL;
10666 }
10667
10668 /*
10669 * The result is used as the new evaluation locset.
10670 */
10671 xmlXPathFreeObject(obj);
10672 ctxt->context->node = NULL;
10673 ctxt->context->contextSize = -1;
10674 ctxt->context->proximityPosition = -1;
10675 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10676 ctxt->context->node = oldnode;
10677 return (total);
10678 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010679#endif /* LIBXML_XPTR_ENABLED */
10680
Daniel Veillardf06307e2001-07-03 10:35:50 +000010681 /*
10682 * Extract the old set, and then evaluate the result of the
10683 * expression for all the element in the set. use it to grow
10684 * up a new set.
10685 */
10686 CHECK_TYPE0(XPATH_NODESET);
10687 obj = valuePop(ctxt);
10688 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010689
Daniel Veillardf06307e2001-07-03 10:35:50 +000010690 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000010691 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010692 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010693
Daniel Veillardf06307e2001-07-03 10:35:50 +000010694 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10695 ctxt->context->contextSize = 0;
10696 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000010697/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000010698 if (op->ch2 != -1)
10699 total +=
10700 xmlXPathCompOpEval(ctxt,
10701 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010702 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010703 res = valuePop(ctxt);
10704 if (res != NULL)
10705 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000010706*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000010707 valuePush(ctxt, obj);
10708 ctxt->context->node = oldnode;
10709 CHECK_ERROR0;
10710 } else {
10711 /*
10712 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000010713 * Also set the xpath document in case things like
10714 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000010715 */
10716 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010717
Daniel Veillardf06307e2001-07-03 10:35:50 +000010718 for (i = 0; i < oldset->nodeNr; i++) {
10719 /*
10720 * Run the evaluation with a node list made of
10721 * a single item in the nodeset.
10722 */
10723 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000010724 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
10725 (oldset->nodeTab[i]->doc != NULL))
10726 ctxt->context->doc = oldset->nodeTab[i]->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010727 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10728 valuePush(ctxt, tmp);
10729 ctxt->context->contextSize = oldset->nodeNr;
10730 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010731
Daniel Veillardf06307e2001-07-03 10:35:50 +000010732 if (op->ch2 != -1)
10733 total +=
10734 xmlXPathCompOpEval(ctxt,
10735 &comp->steps[op->ch2]);
10736 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010737
Daniel Veillardf06307e2001-07-03 10:35:50 +000010738 /*
William M. Brack08171912003-12-29 02:52:11 +000010739 * The result of the evaluation needs to be tested to
10740 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010741 */
10742 res = valuePop(ctxt);
10743 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10744 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10745 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010746
Daniel Veillardf06307e2001-07-03 10:35:50 +000010747 /*
10748 * Cleanup
10749 */
10750 if (res != NULL)
10751 xmlXPathFreeObject(res);
10752 if (ctxt->value == tmp) {
10753 res = valuePop(ctxt);
10754 xmlXPathFreeObject(res);
10755 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010756
Daniel Veillardf06307e2001-07-03 10:35:50 +000010757 ctxt->context->node = NULL;
10758 }
10759
10760 /*
10761 * The result is used as the new evaluation set.
10762 */
10763 xmlXPathFreeObject(obj);
10764 ctxt->context->node = NULL;
10765 ctxt->context->contextSize = -1;
10766 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000010767 /* may want to move this past the '}' later */
10768 ctxt->context->doc = oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010769 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10770 }
10771 ctxt->context->node = oldnode;
10772 return (total);
10773 }
10774 case XPATH_OP_SORT:
10775 if (op->ch1 != -1)
10776 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010777 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010778 if ((ctxt->value != NULL) &&
10779 (ctxt->value->type == XPATH_NODESET) &&
10780 (ctxt->value->nodesetval != NULL))
10781 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10782 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010783#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010784 case XPATH_OP_RANGETO:{
10785 xmlXPathObjectPtr range;
10786 xmlXPathObjectPtr res, obj;
10787 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010788 xmlLocationSetPtr newlocset = NULL;
10789 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010790 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000010791 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010792
Daniel Veillardf06307e2001-07-03 10:35:50 +000010793 if (op->ch1 != -1)
10794 total +=
10795 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10796 if (op->ch2 == -1)
10797 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010798
William M. Brack08171912003-12-29 02:52:11 +000010799 if (ctxt->value->type == XPATH_LOCATIONSET) {
10800 /*
10801 * Extract the old locset, and then evaluate the result of the
10802 * expression for all the element in the locset. use it to grow
10803 * up a new locset.
10804 */
10805 CHECK_TYPE0(XPATH_LOCATIONSET);
10806 obj = valuePop(ctxt);
10807 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010808
William M. Brack08171912003-12-29 02:52:11 +000010809 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000010810 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000010811 ctxt->context->contextSize = 0;
10812 ctxt->context->proximityPosition = 0;
10813 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10814 res = valuePop(ctxt);
10815 if (res != NULL)
10816 xmlXPathFreeObject(res);
10817 valuePush(ctxt, obj);
10818 CHECK_ERROR0;
10819 return (total);
10820 }
10821 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010822
William M. Brack08171912003-12-29 02:52:11 +000010823 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010824 /*
William M. Brack08171912003-12-29 02:52:11 +000010825 * Run the evaluation with a node list made of a
10826 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010827 */
William M. Brackf7eb7942003-12-31 07:59:17 +000010828 ctxt->context->node = oldlocset->locTab[i]->user;
10829 ctxt->context->contextSize = oldlocset->locNr;
10830 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010831 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10832 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010833
Daniel Veillardf06307e2001-07-03 10:35:50 +000010834 if (op->ch2 != -1)
10835 total +=
10836 xmlXPathCompOpEval(ctxt,
10837 &comp->steps[op->ch2]);
10838 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010839
Daniel Veillardf06307e2001-07-03 10:35:50 +000010840 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000010841 if (res->type == XPATH_LOCATIONSET) {
10842 xmlLocationSetPtr rloc =
10843 (xmlLocationSetPtr)res->user;
10844 for (j=0; j<rloc->locNr; j++) {
10845 range = xmlXPtrNewRange(
10846 oldlocset->locTab[i]->user,
10847 oldlocset->locTab[i]->index,
10848 rloc->locTab[j]->user2,
10849 rloc->locTab[j]->index2);
10850 if (range != NULL) {
10851 xmlXPtrLocationSetAdd(newlocset, range);
10852 }
10853 }
10854 } else {
10855 range = xmlXPtrNewRangeNodeObject(
10856 (xmlNodePtr)oldlocset->locTab[i]->user, res);
10857 if (range != NULL) {
10858 xmlXPtrLocationSetAdd(newlocset,range);
10859 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010860 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010861
Daniel Veillardf06307e2001-07-03 10:35:50 +000010862 /*
10863 * Cleanup
10864 */
10865 if (res != NULL)
10866 xmlXPathFreeObject(res);
10867 if (ctxt->value == tmp) {
10868 res = valuePop(ctxt);
10869 xmlXPathFreeObject(res);
10870 }
10871
10872 ctxt->context->node = NULL;
10873 }
William M. Brack72ee48d2003-12-30 08:30:19 +000010874 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000010875 CHECK_TYPE0(XPATH_NODESET);
10876 obj = valuePop(ctxt);
10877 oldset = obj->nodesetval;
10878 ctxt->context->node = NULL;
10879
10880 newlocset = xmlXPtrLocationSetCreate(NULL);
10881
10882 if (oldset != NULL) {
10883 for (i = 0; i < oldset->nodeNr; i++) {
10884 /*
10885 * Run the evaluation with a node list made of a single item
10886 * in the nodeset.
10887 */
10888 ctxt->context->node = oldset->nodeTab[i];
10889 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10890 valuePush(ctxt, tmp);
10891
10892 if (op->ch2 != -1)
10893 total +=
10894 xmlXPathCompOpEval(ctxt,
10895 &comp->steps[op->ch2]);
10896 CHECK_ERROR0;
10897
William M. Brack08171912003-12-29 02:52:11 +000010898 res = valuePop(ctxt);
10899 range =
10900 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10901 res);
10902 if (range != NULL) {
10903 xmlXPtrLocationSetAdd(newlocset, range);
10904 }
10905
10906 /*
10907 * Cleanup
10908 */
10909 if (res != NULL)
10910 xmlXPathFreeObject(res);
10911 if (ctxt->value == tmp) {
10912 res = valuePop(ctxt);
10913 xmlXPathFreeObject(res);
10914 }
10915
10916 ctxt->context->node = NULL;
10917 }
10918 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010919 }
10920
10921 /*
10922 * The result is used as the new evaluation set.
10923 */
10924 xmlXPathFreeObject(obj);
10925 ctxt->context->node = NULL;
10926 ctxt->context->contextSize = -1;
10927 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010928 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010929 return (total);
10930 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010931#endif /* LIBXML_XPTR_ENABLED */
10932 }
10933 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010934 "XPath: unknown precompiled operation %d\n", op->op);
10935 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010936}
10937
Daniel Veillard56de87e2005-02-16 00:22:29 +000010938#ifdef XPATH_STREAMING
10939/**
10940 * xmlXPathRunStreamEval:
10941 * @ctxt: the XPath parser context with the compiled expression
10942 *
10943 * Evaluate the Precompiled Streamable XPath expression in the given context.
10944 */
10945static xmlXPathObjectPtr
10946xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp) {
10947 int max_depth;
10948 int from_root;
10949 int ret, depth;
10950 xmlNodePtr cur, limit;
10951 xmlXPathObjectPtr retval;
10952 xmlStreamCtxtPtr patstream;
10953
10954 int nb_nodes = 0;
10955
10956 if ((ctxt == NULL) || (comp == NULL))
10957 return(NULL);
10958 max_depth = xmlPatternMaxDepth(comp);
10959 if (max_depth == -1)
10960 return(NULL);
10961 if (max_depth == -2)
10962 max_depth = 10000;
10963 from_root = xmlPatternFromRoot(comp);
10964 if (from_root < 0)
10965 return(NULL);
10966/* printf("stream eval: depth %d from root %d\n", max_depth, from_root); */
10967
10968 retval = xmlXPathNewNodeSet(NULL);
10969 if (retval == NULL)
10970 return(NULL);
10971
10972 /* FIXME '. | /' */
10973 if ((from_root) && (max_depth == 0)) {
10974 xmlXPathNodeSetAddUnique(retval->nodesetval, (xmlNodePtr) ctxt->doc);
10975 return(retval);
10976 } else if (max_depth == 0) {
10977 xmlXPathNodeSetAddUnique(retval->nodesetval, ctxt->node);
10978 return(retval);
10979 }
10980 if (from_root) {
10981 cur = ctxt->doc;
10982 limit = NULL;
10983 } else if (ctxt->node != NULL) {
10984 switch (ctxt->node->type) {
10985 case XML_ELEMENT_NODE:
10986 case XML_DOCUMENT_NODE:
10987 case XML_DOCUMENT_FRAG_NODE:
10988 case XML_HTML_DOCUMENT_NODE:
10989#ifdef LIBXML_DOCB_ENABLED
10990 case XML_DOCB_DOCUMENT_NODE:
10991#endif
10992 cur = ctxt->node;
10993 break;
10994 case XML_ATTRIBUTE_NODE:
10995 case XML_TEXT_NODE:
10996 case XML_CDATA_SECTION_NODE:
10997 case XML_ENTITY_REF_NODE:
10998 case XML_ENTITY_NODE:
10999 case XML_PI_NODE:
11000 case XML_COMMENT_NODE:
11001 case XML_NOTATION_NODE:
11002 case XML_DTD_NODE:
11003 case XML_DOCUMENT_TYPE_NODE:
11004 case XML_ELEMENT_DECL:
11005 case XML_ATTRIBUTE_DECL:
11006 case XML_ENTITY_DECL:
11007 case XML_NAMESPACE_DECL:
11008 case XML_XINCLUDE_START:
11009 case XML_XINCLUDE_END:
11010 cur = NULL;
11011 break;
11012 }
11013 limit = cur;
11014 }
11015 if (cur == NULL)
11016 return(retval);
11017
11018 patstream = xmlPatternGetStreamCtxt(comp);
11019 if (patstream == NULL) {
11020 return(retval);
11021 }
11022
11023 if (from_root) {
11024 ret = xmlStreamPush(patstream, NULL, NULL);
11025 if (ret < 0) {
11026 } else if (ret == 1) {
11027 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11028 }
11029 }
11030
11031 depth = 0;
11032 goto scan_children;
11033 do {
11034next_node:
11035 nb_nodes++;
11036 if (cur->type == XML_ELEMENT_NODE) {
11037 ret = xmlStreamPush(patstream, cur->name,
11038 (cur->ns ? cur->ns->href : NULL));
11039 if (ret < 0) {
11040 } else if (ret == 1) {
11041 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11042 }
11043 if ((cur->children == NULL) || (depth >= max_depth)) {
11044 ret = xmlStreamPop(patstream);
11045 }
11046 }
11047
11048scan_children:
11049 if ((cur->children != NULL) && (depth < max_depth)) {
11050 /*
11051 * Do not descend on entities declarations
11052 */
11053 if (cur->children->type != XML_ENTITY_DECL) {
11054 cur = cur->children;
11055 depth++;
11056 /*
11057 * Skip DTDs
11058 */
11059 if (cur->type != XML_DTD_NODE)
11060 continue;
11061 }
11062 }
11063
11064 if (cur == limit)
11065 break;
11066
11067 while (cur->next != NULL) {
11068 cur = cur->next;
11069 if ((cur->type != XML_ENTITY_DECL) &&
11070 (cur->type != XML_DTD_NODE))
11071 goto next_node;
11072 }
11073
11074 do {
11075 ret = xmlStreamPop(patstream);
11076 cur = cur->parent;
11077 depth--;
11078 if ((cur == NULL) || (cur == limit))
11079 goto done;
11080 if (cur->next != NULL) {
11081 cur = cur->next;
11082 break;
11083 }
11084 } while (cur != NULL);
11085
11086 } while ((cur != NULL) && (depth >= 0));
11087done:
11088/* printf("stream eval: checked %d nodes selected %d\n",
11089 nb_nodes, retval->nodesetval->nodeNr); */
11090 xmlFreeStreamCtxt(patstream);
11091 return(retval);
11092}
11093#endif /* XPATH_STREAMING */
11094
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011095/**
11096 * xmlXPathRunEval:
11097 * @ctxt: the XPath parser context with the compiled expression
11098 *
11099 * Evaluate the Precompiled XPath expression in the given context.
11100 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011101static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011102xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
11103 xmlXPathCompExprPtr comp;
11104
11105 if ((ctxt == NULL) || (ctxt->comp == NULL))
11106 return;
11107
11108 if (ctxt->valueTab == NULL) {
11109 /* Allocate the value stack */
11110 ctxt->valueTab = (xmlXPathObjectPtr *)
11111 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
11112 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000011113 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011114 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011115 }
11116 ctxt->valueNr = 0;
11117 ctxt->valueMax = 10;
11118 ctxt->value = NULL;
11119 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011120#ifdef XPATH_STREAMING
11121 if (ctxt->comp->stream) {
11122 xmlXPathObjectPtr ret;
11123 ret = xmlXPathRunStreamEval(ctxt->context, ctxt->comp->stream);
11124 if (ret != NULL) {
11125 valuePush(ctxt, ret);
11126 return;
11127 }
11128 }
11129#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011130 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000011131 if(comp->last < 0) {
11132 xmlGenericError(xmlGenericErrorContext,
11133 "xmlXPathRunEval: last is less than zero\n");
11134 return;
11135 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011136 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11137}
11138
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011139/************************************************************************
11140 * *
11141 * Public interfaces *
11142 * *
11143 ************************************************************************/
11144
11145/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011146 * xmlXPathEvalPredicate:
11147 * @ctxt: the XPath context
11148 * @res: the Predicate Expression evaluation result
11149 *
11150 * Evaluate a predicate result for the current node.
11151 * A PredicateExpr is evaluated by evaluating the Expr and converting
11152 * the result to a boolean. If the result is a number, the result will
11153 * be converted to true if the number is equal to the position of the
11154 * context node in the context node list (as returned by the position
11155 * function) and will be converted to false otherwise; if the result
11156 * is not a number, then the result will be converted as if by a call
11157 * to the boolean function.
11158 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011159 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011160 */
11161int
11162xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000011163 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011164 switch (res->type) {
11165 case XPATH_BOOLEAN:
11166 return(res->boolval);
11167 case XPATH_NUMBER:
11168 return(res->floatval == ctxt->proximityPosition);
11169 case XPATH_NODESET:
11170 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011171 if (res->nodesetval == NULL)
11172 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011173 return(res->nodesetval->nodeNr != 0);
11174 case XPATH_STRING:
11175 return((res->stringval != NULL) &&
11176 (xmlStrlen(res->stringval) != 0));
11177 default:
11178 STRANGE
11179 }
11180 return(0);
11181}
11182
11183/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011184 * xmlXPathEvaluatePredicateResult:
11185 * @ctxt: the XPath Parser context
11186 * @res: the Predicate Expression evaluation result
11187 *
11188 * Evaluate a predicate result for the current node.
11189 * A PredicateExpr is evaluated by evaluating the Expr and converting
11190 * the result to a boolean. If the result is a number, the result will
11191 * be converted to true if the number is equal to the position of the
11192 * context node in the context node list (as returned by the position
11193 * function) and will be converted to false otherwise; if the result
11194 * is not a number, then the result will be converted as if by a call
11195 * to the boolean function.
11196 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011197 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011198 */
11199int
11200xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
11201 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000011202 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011203 switch (res->type) {
11204 case XPATH_BOOLEAN:
11205 return(res->boolval);
11206 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000011207#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000011208 return((res->floatval == ctxt->context->proximityPosition) &&
11209 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000011210#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011211 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000011212#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011213 case XPATH_NODESET:
11214 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000011215 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000011216 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011217 return(res->nodesetval->nodeNr != 0);
11218 case XPATH_STRING:
11219 return((res->stringval != NULL) &&
11220 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000011221#ifdef LIBXML_XPTR_ENABLED
11222 case XPATH_LOCATIONSET:{
11223 xmlLocationSetPtr ptr = res->user;
11224 if (ptr == NULL)
11225 return(0);
11226 return (ptr->locNr != 0);
11227 }
11228#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011229 default:
11230 STRANGE
11231 }
11232 return(0);
11233}
11234
Daniel Veillard56de87e2005-02-16 00:22:29 +000011235#ifdef XPATH_STREAMING
11236/**
11237 * xmlXPathTryStreamCompile:
11238 * @ctxt: an XPath context
11239 * @str: the XPath expression
11240 *
11241 * Try to compile the XPath expression as a streamable subset.
11242 *
11243 * Returns the compiled expression or NULL if failed to compile.
11244 */
11245static xmlXPathCompExprPtr
11246xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11247 /*
11248 * Optimization: use streaming patterns when the XPath expression can
11249 * be compiled to a stream lookup
11250 */
11251 xmlPatternPtr stream;
11252 xmlXPathCompExprPtr comp;
11253 xmlDictPtr dict = NULL;
11254 const xmlChar **namespaces = NULL;
11255 xmlNsPtr ns;
11256 int i, j;
11257
11258 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
11259 (!xmlStrchr(str, '@'))) {
11260 if (ctxt != NULL) {
11261 dict = ctxt->dict;
11262 if (ctxt->nsNr > 0) {
11263 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1));
11264 if (namespaces == NULL) {
11265 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
11266 return(NULL);
11267 }
11268 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
11269 ns = ctxt->namespaces[j];
11270 namespaces[i++] = ns->href;
11271 namespaces[i++] = ns->prefix;
11272 }
11273 namespaces[i++] = NULL;
11274 namespaces[i++] = NULL;
11275 }
11276 }
11277
11278 stream = xmlPatterncompile(str, dict, 0, &namespaces[0]);
11279 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
11280 comp = xmlXPathNewCompExpr();
11281 if (comp == NULL) {
11282 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
11283 return(NULL);
11284 }
11285 comp->stream = stream;
11286 comp->dict = dict;
11287 if (comp->dict)
11288 xmlDictReference(comp->dict);
11289 return(comp);
11290 }
11291 xmlFreePattern(stream);
11292 }
11293 return(NULL);
11294}
11295#endif /* XPATH_STREAMING */
11296
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011297/**
Daniel Veillard4773df22004-01-23 13:15:13 +000011298 * xmlXPathCtxtCompile:
11299 * @ctxt: an XPath context
11300 * @str: the XPath expression
11301 *
11302 * Compile an XPath expression
11303 *
11304 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
11305 * the caller has to free the object.
11306 */
11307xmlXPathCompExprPtr
11308xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11309 xmlXPathParserContextPtr pctxt;
11310 xmlXPathCompExprPtr comp;
11311
Daniel Veillard56de87e2005-02-16 00:22:29 +000011312#ifdef XPATH_STREAMING
11313 comp = xmlXPathTryStreamCompile(ctxt, str);
11314 if (comp != NULL)
11315 return(comp);
11316#endif
11317
Daniel Veillard4773df22004-01-23 13:15:13 +000011318 xmlXPathInit();
11319
11320 pctxt = xmlXPathNewParserContext(str, ctxt);
11321 xmlXPathCompileExpr(pctxt);
11322
11323 if( pctxt->error != XPATH_EXPRESSION_OK )
11324 {
11325 xmlXPathFreeParserContext(pctxt);
11326 return (0);
11327 }
11328
11329 if (*pctxt->cur != 0) {
11330 /*
11331 * aleksey: in some cases this line prints *second* error message
11332 * (see bug #78858) and probably this should be fixed.
11333 * However, we are not sure that all error messages are printed
11334 * out in other places. It's not critical so we leave it as-is for now
11335 */
11336 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11337 comp = NULL;
11338 } else {
11339 comp = pctxt->comp;
11340 pctxt->comp = NULL;
11341 }
11342 xmlXPathFreeParserContext(pctxt);
11343 if (comp != NULL) {
11344 comp->expr = xmlStrdup(str);
11345#ifdef DEBUG_EVAL_COUNTS
11346 comp->string = xmlStrdup(str);
11347 comp->nb = 0;
11348#endif
11349 }
11350 return(comp);
11351}
11352
11353/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011354 * xmlXPathCompile:
11355 * @str: the XPath expression
11356 *
11357 * Compile an XPath expression
11358 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000011359 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011360 * the caller has to free the object.
11361 */
11362xmlXPathCompExprPtr
11363xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000011364 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011365}
11366
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011367/**
11368 * xmlXPathCompiledEval:
11369 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000011370 * @ctx: the XPath context
11371 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011372 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000011373 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011374 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000011375 * the caller has to free the object.
11376 */
11377xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011378xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000011379 xmlXPathParserContextPtr ctxt;
11380 xmlXPathObjectPtr res, tmp, init = NULL;
11381 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000011382#ifndef LIBXML_THREAD_ENABLED
11383 static int reentance = 0;
11384#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011385
William M. Brackf13f77f2004-11-12 16:03:48 +000011386 CHECK_CTXT(ctx)
11387
11388 if (comp == NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011389 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011390 xmlXPathInit();
11391
Daniel Veillard81463942001-10-16 12:34:39 +000011392#ifndef LIBXML_THREAD_ENABLED
11393 reentance++;
11394 if (reentance > 1)
11395 xmlXPathDisableOptimizer = 1;
11396#endif
11397
Daniel Veillardf06307e2001-07-03 10:35:50 +000011398#ifdef DEBUG_EVAL_COUNTS
11399 comp->nb++;
11400 if ((comp->string != NULL) && (comp->nb > 100)) {
11401 fprintf(stderr, "100 x %s\n", comp->string);
11402 comp->nb = 0;
11403 }
11404#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011405 ctxt = xmlXPathCompParserContext(comp, ctx);
11406 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011407
11408 if (ctxt->value == NULL) {
11409 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011410 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011411 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011412 } else {
11413 res = valuePop(ctxt);
11414 }
11415
Daniel Veillardf06307e2001-07-03 10:35:50 +000011416
Owen Taylor3473f882001-02-23 17:55:21 +000011417 do {
11418 tmp = valuePop(ctxt);
11419 if (tmp != NULL) {
11420 if (tmp != init)
11421 stack++;
11422 xmlXPathFreeObject(tmp);
11423 }
11424 } while (tmp != NULL);
11425 if ((stack != 0) && (res != NULL)) {
11426 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011427 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011428 stack);
11429 }
11430 if (ctxt->error != XPATH_EXPRESSION_OK) {
11431 xmlXPathFreeObject(res);
11432 res = NULL;
11433 }
11434
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011435
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011436 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011437 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011438#ifndef LIBXML_THREAD_ENABLED
11439 reentance--;
11440#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011441 return(res);
11442}
11443
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011444/**
11445 * xmlXPathEvalExpr:
11446 * @ctxt: the XPath Parser context
11447 *
11448 * Parse and evaluate an XPath expression in the given context,
11449 * then push the result on the context stack
11450 */
11451void
11452xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011453#ifdef XPATH_STREAMING
11454 xmlXPathCompExprPtr comp;
11455#endif
11456
Daniel Veillarda82b1822004-11-08 16:24:57 +000011457 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011458
11459#ifdef XPATH_STREAMING
11460 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
11461 if (comp != NULL) {
11462 if (ctxt->comp != NULL)
11463 xmlXPathFreeCompExpr(ctxt->comp);
11464 ctxt->comp = comp;
11465 if (ctxt->cur != NULL)
11466 while (*ctxt->cur != 0) ctxt->cur++;
11467 } else
11468#endif
11469 {
11470 xmlXPathCompileExpr(ctxt);
11471 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011472 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011473 xmlXPathRunEval(ctxt);
11474}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011475
11476/**
11477 * xmlXPathEval:
11478 * @str: the XPath expression
11479 * @ctx: the XPath context
11480 *
11481 * Evaluate the XPath Location Path in the given context.
11482 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011483 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011484 * the caller has to free the object.
11485 */
11486xmlXPathObjectPtr
11487xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11488 xmlXPathParserContextPtr ctxt;
11489 xmlXPathObjectPtr res, tmp, init = NULL;
11490 int stack = 0;
11491
William M. Brackf13f77f2004-11-12 16:03:48 +000011492 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011493
William M. Brackf13f77f2004-11-12 16:03:48 +000011494 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011495
11496 ctxt = xmlXPathNewParserContext(str, ctx);
11497 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011498
11499 if (ctxt->value == NULL) {
11500 xmlGenericError(xmlGenericErrorContext,
11501 "xmlXPathEval: evaluation failed\n");
11502 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011503 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
11504#ifdef XPATH_STREAMING
11505 && (ctxt->comp->stream == NULL)
11506#endif
11507 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011508 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11509 res = NULL;
11510 } else {
11511 res = valuePop(ctxt);
11512 }
11513
11514 do {
11515 tmp = valuePop(ctxt);
11516 if (tmp != NULL) {
11517 if (tmp != init)
11518 stack++;
11519 xmlXPathFreeObject(tmp);
11520 }
11521 } while (tmp != NULL);
11522 if ((stack != 0) && (res != NULL)) {
11523 xmlGenericError(xmlGenericErrorContext,
11524 "xmlXPathEval: %d object left on the stack\n",
11525 stack);
11526 }
11527 if (ctxt->error != XPATH_EXPRESSION_OK) {
11528 xmlXPathFreeObject(res);
11529 res = NULL;
11530 }
11531
Owen Taylor3473f882001-02-23 17:55:21 +000011532 xmlXPathFreeParserContext(ctxt);
11533 return(res);
11534}
11535
11536/**
11537 * xmlXPathEvalExpression:
11538 * @str: the XPath expression
11539 * @ctxt: the XPath context
11540 *
11541 * Evaluate the XPath expression in the given context.
11542 *
11543 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11544 * the caller has to free the object.
11545 */
11546xmlXPathObjectPtr
11547xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11548 xmlXPathParserContextPtr pctxt;
11549 xmlXPathObjectPtr res, tmp;
11550 int stack = 0;
11551
William M. Brackf13f77f2004-11-12 16:03:48 +000011552 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000011553
William M. Brackf13f77f2004-11-12 16:03:48 +000011554 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000011555
11556 pctxt = xmlXPathNewParserContext(str, ctxt);
11557 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011558
11559 if (*pctxt->cur != 0) {
11560 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11561 res = NULL;
11562 } else {
11563 res = valuePop(pctxt);
11564 }
11565 do {
11566 tmp = valuePop(pctxt);
11567 if (tmp != NULL) {
11568 xmlXPathFreeObject(tmp);
11569 stack++;
11570 }
11571 } while (tmp != NULL);
11572 if ((stack != 0) && (res != NULL)) {
11573 xmlGenericError(xmlGenericErrorContext,
11574 "xmlXPathEvalExpression: %d object left on the stack\n",
11575 stack);
11576 }
11577 xmlXPathFreeParserContext(pctxt);
11578 return(res);
11579}
11580
Daniel Veillard42766c02002-08-22 20:52:17 +000011581/************************************************************************
11582 * *
11583 * Extra functions not pertaining to the XPath spec *
11584 * *
11585 ************************************************************************/
11586/**
11587 * xmlXPathEscapeUriFunction:
11588 * @ctxt: the XPath Parser context
11589 * @nargs: the number of arguments
11590 *
11591 * Implement the escape-uri() XPath function
11592 * string escape-uri(string $str, bool $escape-reserved)
11593 *
11594 * This function applies the URI escaping rules defined in section 2 of [RFC
11595 * 2396] to the string supplied as $uri-part, which typically represents all
11596 * or part of a URI. The effect of the function is to replace any special
11597 * character in the string by an escape sequence of the form %xx%yy...,
11598 * where xxyy... is the hexadecimal representation of the octets used to
11599 * represent the character in UTF-8.
11600 *
11601 * The set of characters that are escaped depends on the setting of the
11602 * boolean argument $escape-reserved.
11603 *
11604 * If $escape-reserved is true, all characters are escaped other than lower
11605 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11606 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11607 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11608 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11609 * A-F).
11610 *
11611 * If $escape-reserved is false, the behavior differs in that characters
11612 * referred to in [RFC 2396] as reserved characters are not escaped. These
11613 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11614 *
11615 * [RFC 2396] does not define whether escaped URIs should use lower case or
11616 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11617 * compared using string comparison functions, this function must always use
11618 * the upper-case letters A-F.
11619 *
11620 * Generally, $escape-reserved should be set to true when escaping a string
11621 * that is to form a single part of a URI, and to false when escaping an
11622 * entire URI or URI reference.
11623 *
11624 * In the case of non-ascii characters, the string is encoded according to
11625 * utf-8 and then converted according to RFC 2396.
11626 *
11627 * Examples
11628 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11629 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11630 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11631 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11632 *
11633 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011634static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011635xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11636 xmlXPathObjectPtr str;
11637 int escape_reserved;
11638 xmlBufferPtr target;
11639 xmlChar *cptr;
11640 xmlChar escape[4];
11641
11642 CHECK_ARITY(2);
11643
11644 escape_reserved = xmlXPathPopBoolean(ctxt);
11645
11646 CAST_TO_STRING;
11647 str = valuePop(ctxt);
11648
11649 target = xmlBufferCreate();
11650
11651 escape[0] = '%';
11652 escape[3] = 0;
11653
11654 if (target) {
11655 for (cptr = str->stringval; *cptr; cptr++) {
11656 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11657 (*cptr >= 'a' && *cptr <= 'z') ||
11658 (*cptr >= '0' && *cptr <= '9') ||
11659 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11660 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11661 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11662 (*cptr == '%' &&
11663 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11664 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11665 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11666 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11667 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11668 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11669 (!escape_reserved &&
11670 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11671 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11672 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11673 *cptr == ','))) {
11674 xmlBufferAdd(target, cptr, 1);
11675 } else {
11676 if ((*cptr >> 4) < 10)
11677 escape[1] = '0' + (*cptr >> 4);
11678 else
11679 escape[1] = 'A' - 10 + (*cptr >> 4);
11680 if ((*cptr & 0xF) < 10)
11681 escape[2] = '0' + (*cptr & 0xF);
11682 else
11683 escape[2] = 'A' - 10 + (*cptr & 0xF);
11684
11685 xmlBufferAdd(target, &escape[0], 3);
11686 }
11687 }
11688 }
11689 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11690 xmlBufferFree(target);
11691 xmlXPathFreeObject(str);
11692}
11693
Owen Taylor3473f882001-02-23 17:55:21 +000011694/**
11695 * xmlXPathRegisterAllFunctions:
11696 * @ctxt: the XPath context
11697 *
11698 * Registers all default XPath functions in this context
11699 */
11700void
11701xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11702{
11703 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11704 xmlXPathBooleanFunction);
11705 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11706 xmlXPathCeilingFunction);
11707 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11708 xmlXPathCountFunction);
11709 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11710 xmlXPathConcatFunction);
11711 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11712 xmlXPathContainsFunction);
11713 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11714 xmlXPathIdFunction);
11715 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11716 xmlXPathFalseFunction);
11717 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11718 xmlXPathFloorFunction);
11719 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11720 xmlXPathLastFunction);
11721 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11722 xmlXPathLangFunction);
11723 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11724 xmlXPathLocalNameFunction);
11725 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11726 xmlXPathNotFunction);
11727 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11728 xmlXPathNameFunction);
11729 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11730 xmlXPathNamespaceURIFunction);
11731 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11732 xmlXPathNormalizeFunction);
11733 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11734 xmlXPathNumberFunction);
11735 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11736 xmlXPathPositionFunction);
11737 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11738 xmlXPathRoundFunction);
11739 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11740 xmlXPathStringFunction);
11741 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11742 xmlXPathStringLengthFunction);
11743 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11744 xmlXPathStartsWithFunction);
11745 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11746 xmlXPathSubstringFunction);
11747 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11748 xmlXPathSubstringBeforeFunction);
11749 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11750 xmlXPathSubstringAfterFunction);
11751 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11752 xmlXPathSumFunction);
11753 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11754 xmlXPathTrueFunction);
11755 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11756 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011757
11758 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11759 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11760 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011761}
11762
11763#endif /* LIBXML_XPATH_ENABLED */