blob: 0e42893def2af06c75f0048cc0e8b935eb14f58d [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
Owen Taylor3473f882001-02-23 17:55:21 +000031#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000034#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000035#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#endif
Owen Taylor3473f882001-02-23 17:55:21 +000037
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000052#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000053#include <libxml/globals.h>
Daniel Veillard56de87e2005-02-16 00:22:29 +000054#ifdef LIBXML_PATTERN_ENABLED
55#include <libxml/pattern.h>
56#endif
57
58#ifdef LIBXML_PATTERN_ENABLED
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000059#define XPATH_STREAMING
Daniel Veillard56de87e2005-02-16 00:22:29 +000060#endif
Owen Taylor3473f882001-02-23 17:55:21 +000061
Daniel Veillardd96f6d32003-10-07 21:25:12 +000062#define TODO \
63 xmlGenericError(xmlGenericErrorContext, \
64 "Unimplemented block at %s:%d\n", \
65 __FILE__, __LINE__);
66
William M. Brackd1757ab2004-10-02 22:07:48 +000067/*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000068* XP_PATTERN_TO_ANY_NODE_ENABLED: when an XPath expression can be
69* evaluated using the streaming mode (pattern.c) then this is used to
70* enable resolution to nodes of type text-node, cdata-section-node,
71* comment-node and pi-node. The only known scenario where this is
72* needed is an expression like "foo//.", "//.", etc.; i.e. an expression
73* where the final node to be selected can be of any type.
74* Disabling this #define will result in an incorrect evaluation to
75* only element-nodes and the document node.
76*/
77#define XP_PATTERN_TO_ANY_NODE_ENABLED
78/*
William M. Brackd1757ab2004-10-02 22:07:48 +000079 * TODO:
80 * There are a few spots where some tests are done which depend upon ascii
81 * data. These should be enhanced for full UTF8 support (see particularly
82 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
83 */
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000084
William M. Brack21e4ef22005-01-02 09:53:13 +000085#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000086/************************************************************************
87 * *
88 * Floating point stuff *
89 * *
90 ************************************************************************/
91
Daniel Veillardc0631a62001-09-20 13:56:06 +000092#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000093#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000094#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000095#include "trionan.c"
96
Owen Taylor3473f882001-02-23 17:55:21 +000097/*
Owen Taylor3473f882001-02-23 17:55:21 +000098 * The lack of portability of this section of the libc is annoying !
99 */
100double xmlXPathNAN = 0;
101double xmlXPathPINF = 1;
102double xmlXPathNINF = -1;
Daniel Veillard24505b02005-07-28 23:49:35 +0000103static double xmlXPathNZERO = 0; /* not exported from headers */
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000104static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000105
Owen Taylor3473f882001-02-23 17:55:21 +0000106/**
107 * xmlXPathInit:
108 *
109 * Initialize the XPath environment
110 */
111void
112xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000113 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000114
Bjorn Reese45029602001-08-21 09:23:53 +0000115 xmlXPathPINF = trio_pinf();
116 xmlXPathNINF = trio_ninf();
117 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000118 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000119
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000120 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000121}
122
Daniel Veillardcda96922001-08-21 10:56:31 +0000123/**
124 * xmlXPathIsNaN:
125 * @val: a double value
126 *
127 * Provides a portable isnan() function to detect whether a double
128 * is a NotaNumber. Based on trio code
129 * http://sourceforge.net/projects/ctrio/
130 *
131 * Returns 1 if the value is a NaN, 0 otherwise
132 */
133int
134xmlXPathIsNaN(double val) {
135 return(trio_isnan(val));
136}
137
138/**
139 * xmlXPathIsInf:
140 * @val: a double value
141 *
142 * Provides a portable isinf() function to detect whether a double
143 * is a +Infinite or -Infinite. Based on trio code
144 * http://sourceforge.net/projects/ctrio/
145 *
146 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
147 */
148int
149xmlXPathIsInf(double val) {
150 return(trio_isinf(val));
151}
152
Daniel Veillard4432df22003-09-28 18:58:27 +0000153#endif /* SCHEMAS or XPATH */
154#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000155/**
156 * xmlXPathGetSign:
157 * @val: a double value
158 *
159 * Provides a portable function to detect the sign of a double
160 * Modified from trio code
161 * http://sourceforge.net/projects/ctrio/
162 *
163 * Returns 1 if the value is Negative, 0 if positive
164 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000165static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000166xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000167 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000168}
169
170
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000171/*
172 * TODO: when compatibility allows remove all "fake node libxslt" strings
173 * the test should just be name[0] = ' '
174 */
175/* #define DEBUG */
176/* #define DEBUG_STEP */
177/* #define DEBUG_STEP_NTH */
178/* #define DEBUG_EXPR */
179/* #define DEBUG_EVAL_COUNTS */
180
181static xmlNs xmlXPathXMLNamespaceStruct = {
182 NULL,
183 XML_NAMESPACE_DECL,
184 XML_XML_NAMESPACE,
185 BAD_CAST "xml",
186 NULL
187};
188static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
189#ifndef LIBXML_THREAD_ENABLED
190/*
191 * Optimizer is disabled only when threaded apps are detected while
192 * the library ain't compiled for thread safety.
193 */
194static int xmlXPathDisableOptimizer = 0;
195#endif
196
Owen Taylor3473f882001-02-23 17:55:21 +0000197/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000198 * *
199 * Error handling routines *
200 * *
201 ************************************************************************/
202
Daniel Veillard24505b02005-07-28 23:49:35 +0000203/**
204 * XP_ERRORNULL:
205 * @X: the error code
206 *
207 * Macro to raise an XPath error and return NULL.
208 */
209#define XP_ERRORNULL(X) \
210 { xmlXPathErr(ctxt, X); return(NULL); }
211
William M. Brack08171912003-12-29 02:52:11 +0000212/*
213 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
214 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000215static const char *xmlXPathErrorMessages[] = {
216 "Ok\n",
217 "Number encoding\n",
218 "Unfinished literal\n",
219 "Start of literal\n",
220 "Expected $ for variable reference\n",
221 "Undefined variable\n",
222 "Invalid predicate\n",
223 "Invalid expression\n",
224 "Missing closing curly brace\n",
225 "Unregistered function\n",
226 "Invalid operand\n",
227 "Invalid type\n",
228 "Invalid number of arguments\n",
229 "Invalid context size\n",
230 "Invalid context position\n",
231 "Memory allocation error\n",
232 "Syntax error\n",
233 "Resource error\n",
234 "Sub resource error\n",
235 "Undefined namespace prefix\n",
236 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000237 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000238 "Invalid or incomplete context\n",
239 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000240};
William M. Brackcd65bc92005-01-06 09:39:18 +0000241#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
242 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000243/**
244 * xmlXPathErrMemory:
245 * @ctxt: an XPath context
246 * @extra: extra informations
247 *
248 * Handle a redefinition of attribute error
249 */
250static void
251xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
252{
253 if (ctxt != NULL) {
254 if (extra) {
255 xmlChar buf[200];
256
257 xmlStrPrintf(buf, 200,
258 BAD_CAST "Memory allocation failed : %s\n",
259 extra);
260 ctxt->lastError.message = (char *) xmlStrdup(buf);
261 } else {
262 ctxt->lastError.message = (char *)
263 xmlStrdup(BAD_CAST "Memory allocation failed\n");
264 }
265 ctxt->lastError.domain = XML_FROM_XPATH;
266 ctxt->lastError.code = XML_ERR_NO_MEMORY;
267 if (ctxt->error != NULL)
268 ctxt->error(ctxt->userData, &ctxt->lastError);
269 } else {
270 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000271 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000272 NULL, NULL, XML_FROM_XPATH,
273 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
274 extra, NULL, NULL, 0, 0,
275 "Memory allocation failed : %s\n", extra);
276 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000277 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000278 NULL, NULL, XML_FROM_XPATH,
279 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
280 NULL, NULL, NULL, 0, 0,
281 "Memory allocation failed\n");
282 }
283}
284
285/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000286 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000287 * @ctxt: an XPath parser context
288 * @extra: extra informations
289 *
290 * Handle a redefinition of attribute error
291 */
292static void
293xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
294{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000295 if (ctxt == NULL)
296 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000297 else {
298 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000299 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000300 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000301}
302
303/**
304 * xmlXPathErr:
305 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000306 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000307 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000308 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000309 */
310void
311xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
312{
William M. Brackcd65bc92005-01-06 09:39:18 +0000313 if ((error < 0) || (error > MAXERRNO))
314 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000315 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000316 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000317 NULL, NULL, XML_FROM_XPATH,
318 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
319 XML_ERR_ERROR, NULL, 0,
320 NULL, NULL, NULL, 0, 0,
321 xmlXPathErrorMessages[error]);
322 return;
323 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000324 ctxt->error = error;
325 if (ctxt->context == NULL) {
326 __xmlRaiseError(NULL, NULL, NULL,
327 NULL, NULL, XML_FROM_XPATH,
328 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
329 XML_ERR_ERROR, NULL, 0,
330 (const char *) ctxt->base, NULL, NULL,
331 ctxt->cur - ctxt->base, 0,
332 xmlXPathErrorMessages[error]);
333 return;
334 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000335 ctxt->context->lastError.domain = XML_FROM_XPATH;
336 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
337 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000338 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000339 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
340 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
341 ctxt->context->lastError.node = ctxt->context->debugNode;
342 if (ctxt->context->error != NULL) {
343 ctxt->context->error(ctxt->context->userData,
344 &ctxt->context->lastError);
345 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000346 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000347 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
348 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
349 XML_ERR_ERROR, NULL, 0,
350 (const char *) ctxt->base, NULL, NULL,
351 ctxt->cur - ctxt->base, 0,
352 xmlXPathErrorMessages[error]);
353 }
354
355}
356
357/**
358 * xmlXPatherror:
359 * @ctxt: the XPath Parser context
360 * @file: the file name
361 * @line: the line number
362 * @no: the error number
363 *
364 * Formats an error message.
365 */
366void
367xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
368 int line ATTRIBUTE_UNUSED, int no) {
369 xmlXPathErr(ctxt, no);
370}
371
372
373/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000374 * *
375 * Parser Types *
376 * *
377 ************************************************************************/
378
379/*
380 * Types are private:
381 */
382
383typedef enum {
384 XPATH_OP_END=0,
385 XPATH_OP_AND,
386 XPATH_OP_OR,
387 XPATH_OP_EQUAL,
388 XPATH_OP_CMP,
389 XPATH_OP_PLUS,
390 XPATH_OP_MULT,
391 XPATH_OP_UNION,
392 XPATH_OP_ROOT,
393 XPATH_OP_NODE,
394 XPATH_OP_RESET,
395 XPATH_OP_COLLECT,
396 XPATH_OP_VALUE,
397 XPATH_OP_VARIABLE,
398 XPATH_OP_FUNCTION,
399 XPATH_OP_ARG,
400 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000401 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000402 XPATH_OP_SORT
403#ifdef LIBXML_XPTR_ENABLED
404 ,XPATH_OP_RANGETO
405#endif
406} xmlXPathOp;
407
408typedef enum {
409 AXIS_ANCESTOR = 1,
410 AXIS_ANCESTOR_OR_SELF,
411 AXIS_ATTRIBUTE,
412 AXIS_CHILD,
413 AXIS_DESCENDANT,
414 AXIS_DESCENDANT_OR_SELF,
415 AXIS_FOLLOWING,
416 AXIS_FOLLOWING_SIBLING,
417 AXIS_NAMESPACE,
418 AXIS_PARENT,
419 AXIS_PRECEDING,
420 AXIS_PRECEDING_SIBLING,
421 AXIS_SELF
422} xmlXPathAxisVal;
423
424typedef enum {
425 NODE_TEST_NONE = 0,
426 NODE_TEST_TYPE = 1,
427 NODE_TEST_PI = 2,
428 NODE_TEST_ALL = 3,
429 NODE_TEST_NS = 4,
430 NODE_TEST_NAME = 5
431} xmlXPathTestVal;
432
433typedef enum {
434 NODE_TYPE_NODE = 0,
435 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
436 NODE_TYPE_TEXT = XML_TEXT_NODE,
437 NODE_TYPE_PI = XML_PI_NODE
438} xmlXPathTypeVal;
439
440
441typedef struct _xmlXPathStepOp xmlXPathStepOp;
442typedef xmlXPathStepOp *xmlXPathStepOpPtr;
443struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000444 xmlXPathOp op; /* The identifier of the operation */
445 int ch1; /* First child */
446 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000447 int value;
448 int value2;
449 int value3;
450 void *value4;
451 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000452 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000453 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000454};
455
456struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000457 int nbStep; /* Number of steps in this expression */
458 int maxStep; /* Maximum number of steps allocated */
459 xmlXPathStepOp *steps; /* ops for computation of this expression */
460 int last; /* index of last step in expression */
461 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000462 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000463#ifdef DEBUG_EVAL_COUNTS
464 int nb;
465 xmlChar *string;
466#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000467#ifdef XPATH_STREAMING
468 xmlPatternPtr stream;
469#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000470};
471
472/************************************************************************
473 * *
474 * Parser Type functions *
475 * *
476 ************************************************************************/
477
478/**
479 * xmlXPathNewCompExpr:
480 *
481 * Create a new Xpath component
482 *
483 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
484 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000485static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000486xmlXPathNewCompExpr(void) {
487 xmlXPathCompExprPtr cur;
488
489 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
490 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000491 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000492 return(NULL);
493 }
494 memset(cur, 0, sizeof(xmlXPathCompExpr));
495 cur->maxStep = 10;
496 cur->nbStep = 0;
497 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
498 sizeof(xmlXPathStepOp));
499 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000500 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000501 xmlFree(cur);
502 return(NULL);
503 }
504 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
505 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000506#ifdef DEBUG_EVAL_COUNTS
507 cur->nb = 0;
508#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000509 return(cur);
510}
511
512/**
513 * xmlXPathFreeCompExpr:
514 * @comp: an XPATH comp
515 *
516 * Free up the memory allocated by @comp
517 */
518void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000519xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
520{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000521 xmlXPathStepOpPtr op;
522 int i;
523
524 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000525 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000526 if (comp->dict == NULL) {
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 else
533 xmlFree(op->value4);
534 }
535 if (op->value5 != NULL)
536 xmlFree(op->value5);
537 }
538 } else {
539 for (i = 0; i < comp->nbStep; i++) {
540 op = &comp->steps[i];
541 if (op->value4 != NULL) {
542 if (op->op == XPATH_OP_VALUE)
543 xmlXPathFreeObject(op->value4);
544 }
545 }
546 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000547 }
548 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000549 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000550 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000551#ifdef DEBUG_EVAL_COUNTS
552 if (comp->string != NULL) {
553 xmlFree(comp->string);
554 }
555#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000556#ifdef XPATH_STREAMING
557 if (comp->stream != NULL) {
558 xmlFreePatternList(comp->stream);
559 }
560#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000561 if (comp->expr != NULL) {
562 xmlFree(comp->expr);
563 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000564
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000565 xmlFree(comp);
566}
567
568/**
569 * xmlXPathCompExprAdd:
570 * @comp: the compiled expression
571 * @ch1: first child index
572 * @ch2: second child index
573 * @op: an op
574 * @value: the first int value
575 * @value2: the second int value
576 * @value3: the third int value
577 * @value4: the first string value
578 * @value5: the second string value
579 *
William M. Brack08171912003-12-29 02:52:11 +0000580 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000581 *
582 * Returns -1 in case of failure, the index otherwise
583 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000584static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000585xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
586 xmlXPathOp op, int value,
587 int value2, int value3, void *value4, void *value5) {
588 if (comp->nbStep >= comp->maxStep) {
589 xmlXPathStepOp *real;
590
591 comp->maxStep *= 2;
592 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
593 comp->maxStep * sizeof(xmlXPathStepOp));
594 if (real == NULL) {
595 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000596 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000597 return(-1);
598 }
599 comp->steps = real;
600 }
601 comp->last = comp->nbStep;
602 comp->steps[comp->nbStep].ch1 = ch1;
603 comp->steps[comp->nbStep].ch2 = ch2;
604 comp->steps[comp->nbStep].op = op;
605 comp->steps[comp->nbStep].value = value;
606 comp->steps[comp->nbStep].value2 = value2;
607 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000608 if ((comp->dict != NULL) &&
609 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
610 (op == XPATH_OP_COLLECT))) {
611 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000612 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000613 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000614 xmlFree(value4);
615 } else
616 comp->steps[comp->nbStep].value4 = NULL;
617 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000618 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000619 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000620 xmlFree(value5);
621 } else
622 comp->steps[comp->nbStep].value5 = NULL;
623 } else {
624 comp->steps[comp->nbStep].value4 = value4;
625 comp->steps[comp->nbStep].value5 = value5;
626 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000627 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000628 return(comp->nbStep++);
629}
630
Daniel Veillardf06307e2001-07-03 10:35:50 +0000631/**
632 * xmlXPathCompSwap:
633 * @comp: the compiled expression
634 * @op: operation index
635 *
636 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000637 */
638static void
639xmlXPathCompSwap(xmlXPathStepOpPtr op) {
640 int tmp;
641
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000642#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000643 /*
644 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000645 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000646 * application
647 */
648 if (xmlXPathDisableOptimizer)
649 return;
650#endif
651
Daniel Veillardf06307e2001-07-03 10:35:50 +0000652 tmp = op->ch1;
653 op->ch1 = op->ch2;
654 op->ch2 = tmp;
655}
656
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000657#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
658 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
659 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000660#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
661 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
662 (op), (val), (val2), (val3), (val4), (val5))
663
664#define PUSH_LEAVE_EXPR(op, val, val2) \
665xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
666
667#define PUSH_UNARY_EXPR(op, ch, val, val2) \
668xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
669
670#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000671xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
672 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000673
674/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000675 * *
676 * Debugging related functions *
677 * *
678 ************************************************************************/
679
Owen Taylor3473f882001-02-23 17:55:21 +0000680#define STRANGE \
681 xmlGenericError(xmlGenericErrorContext, \
682 "Internal error at %s:%d\n", \
683 __FILE__, __LINE__);
684
685#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000686static void
687xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000688 int i;
689 char shift[100];
690
691 for (i = 0;((i < depth) && (i < 25));i++)
692 shift[2 * i] = shift[2 * i + 1] = ' ';
693 shift[2 * i] = shift[2 * i + 1] = 0;
694 if (cur == NULL) {
695 fprintf(output, shift);
696 fprintf(output, "Node is NULL !\n");
697 return;
698
699 }
700
701 if ((cur->type == XML_DOCUMENT_NODE) ||
702 (cur->type == XML_HTML_DOCUMENT_NODE)) {
703 fprintf(output, shift);
704 fprintf(output, " /\n");
705 } else if (cur->type == XML_ATTRIBUTE_NODE)
706 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
707 else
708 xmlDebugDumpOneNode(output, cur, depth);
709}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000710static void
711xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000712 xmlNodePtr tmp;
713 int i;
714 char shift[100];
715
716 for (i = 0;((i < depth) && (i < 25));i++)
717 shift[2 * i] = shift[2 * i + 1] = ' ';
718 shift[2 * i] = shift[2 * i + 1] = 0;
719 if (cur == NULL) {
720 fprintf(output, shift);
721 fprintf(output, "Node is NULL !\n");
722 return;
723
724 }
725
726 while (cur != NULL) {
727 tmp = cur;
728 cur = cur->next;
729 xmlDebugDumpOneNode(output, tmp, depth);
730 }
731}
Owen Taylor3473f882001-02-23 17:55:21 +0000732
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000733static void
734xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000735 int i;
736 char shift[100];
737
738 for (i = 0;((i < depth) && (i < 25));i++)
739 shift[2 * i] = shift[2 * i + 1] = ' ';
740 shift[2 * i] = shift[2 * i + 1] = 0;
741
742 if (cur == NULL) {
743 fprintf(output, shift);
744 fprintf(output, "NodeSet is NULL !\n");
745 return;
746
747 }
748
Daniel Veillard911f49a2001-04-07 15:39:35 +0000749 if (cur != NULL) {
750 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
751 for (i = 0;i < cur->nodeNr;i++) {
752 fprintf(output, shift);
753 fprintf(output, "%d", i + 1);
754 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
755 }
Owen Taylor3473f882001-02-23 17:55:21 +0000756 }
757}
758
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000759static void
760xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000761 int i;
762 char shift[100];
763
764 for (i = 0;((i < depth) && (i < 25));i++)
765 shift[2 * i] = shift[2 * i + 1] = ' ';
766 shift[2 * i] = shift[2 * i + 1] = 0;
767
768 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
769 fprintf(output, shift);
770 fprintf(output, "Value Tree is NULL !\n");
771 return;
772
773 }
774
775 fprintf(output, shift);
776 fprintf(output, "%d", i + 1);
777 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
778}
Owen Taylor3473f882001-02-23 17:55:21 +0000779#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000780static void
781xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000782 int i;
783 char shift[100];
784
785 for (i = 0;((i < depth) && (i < 25));i++)
786 shift[2 * i] = shift[2 * i + 1] = ' ';
787 shift[2 * i] = shift[2 * i + 1] = 0;
788
789 if (cur == NULL) {
790 fprintf(output, shift);
791 fprintf(output, "LocationSet is NULL !\n");
792 return;
793
794 }
795
796 for (i = 0;i < cur->locNr;i++) {
797 fprintf(output, shift);
798 fprintf(output, "%d : ", i + 1);
799 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
800 }
801}
Daniel Veillard017b1082001-06-21 11:20:21 +0000802#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000803
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000804/**
805 * xmlXPathDebugDumpObject:
806 * @output: the FILE * to dump the output
807 * @cur: the object to inspect
808 * @depth: indentation level
809 *
810 * Dump the content of the object for debugging purposes
811 */
812void
813xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000814 int i;
815 char shift[100];
816
Daniel Veillarda82b1822004-11-08 16:24:57 +0000817 if (output == NULL) return;
818
Owen Taylor3473f882001-02-23 17:55:21 +0000819 for (i = 0;((i < depth) && (i < 25));i++)
820 shift[2 * i] = shift[2 * i + 1] = ' ';
821 shift[2 * i] = shift[2 * i + 1] = 0;
822
Kasimier T. Buchcik97258712006-01-05 12:30:43 +0000823
824 fprintf(output, shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000825
826 if (cur == NULL) {
827 fprintf(output, "Object is empty (NULL)\n");
828 return;
829 }
830 switch(cur->type) {
831 case XPATH_UNDEFINED:
832 fprintf(output, "Object is uninitialized\n");
833 break;
834 case XPATH_NODESET:
835 fprintf(output, "Object is a Node Set :\n");
836 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
837 break;
838 case XPATH_XSLT_TREE:
839 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000840 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000841 break;
842 case XPATH_BOOLEAN:
843 fprintf(output, "Object is a Boolean : ");
844 if (cur->boolval) fprintf(output, "true\n");
845 else fprintf(output, "false\n");
846 break;
847 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000848 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000849 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000850 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000851 break;
852 case -1:
853 fprintf(output, "Object is a number : -Infinity\n");
854 break;
855 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000856 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000857 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000858 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
859 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000860 } else {
861 fprintf(output, "Object is a number : %0g\n", cur->floatval);
862 }
863 }
Owen Taylor3473f882001-02-23 17:55:21 +0000864 break;
865 case XPATH_STRING:
866 fprintf(output, "Object is a string : ");
867 xmlDebugDumpString(output, cur->stringval);
868 fprintf(output, "\n");
869 break;
870 case XPATH_POINT:
871 fprintf(output, "Object is a point : index %d in node", cur->index);
872 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
873 fprintf(output, "\n");
874 break;
875 case XPATH_RANGE:
876 if ((cur->user2 == NULL) ||
877 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
878 fprintf(output, "Object is a collapsed range :\n");
879 fprintf(output, shift);
880 if (cur->index >= 0)
881 fprintf(output, "index %d in ", cur->index);
882 fprintf(output, "node\n");
883 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
884 depth + 1);
885 } else {
886 fprintf(output, "Object is a range :\n");
887 fprintf(output, shift);
888 fprintf(output, "From ");
889 if (cur->index >= 0)
890 fprintf(output, "index %d in ", cur->index);
891 fprintf(output, "node\n");
892 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
893 depth + 1);
894 fprintf(output, shift);
895 fprintf(output, "To ");
896 if (cur->index2 >= 0)
897 fprintf(output, "index %d in ", cur->index2);
898 fprintf(output, "node\n");
899 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
900 depth + 1);
901 fprintf(output, "\n");
902 }
903 break;
904 case XPATH_LOCATIONSET:
905#if defined(LIBXML_XPTR_ENABLED)
906 fprintf(output, "Object is a Location Set:\n");
907 xmlXPathDebugDumpLocationSet(output,
908 (xmlLocationSetPtr) cur->user, depth);
909#endif
910 break;
911 case XPATH_USERS:
912 fprintf(output, "Object is user defined\n");
913 break;
914 }
915}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000916
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000917static void
918xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000919 xmlXPathStepOpPtr op, int depth) {
920 int i;
921 char shift[100];
922
923 for (i = 0;((i < depth) && (i < 25));i++)
924 shift[2 * i] = shift[2 * i + 1] = ' ';
925 shift[2 * i] = shift[2 * i + 1] = 0;
926
927 fprintf(output, shift);
928 if (op == NULL) {
929 fprintf(output, "Step is NULL\n");
930 return;
931 }
932 switch (op->op) {
933 case XPATH_OP_END:
934 fprintf(output, "END"); break;
935 case XPATH_OP_AND:
936 fprintf(output, "AND"); break;
937 case XPATH_OP_OR:
938 fprintf(output, "OR"); break;
939 case XPATH_OP_EQUAL:
940 if (op->value)
941 fprintf(output, "EQUAL =");
942 else
943 fprintf(output, "EQUAL !=");
944 break;
945 case XPATH_OP_CMP:
946 if (op->value)
947 fprintf(output, "CMP <");
948 else
949 fprintf(output, "CMP >");
950 if (!op->value2)
951 fprintf(output, "=");
952 break;
953 case XPATH_OP_PLUS:
954 if (op->value == 0)
955 fprintf(output, "PLUS -");
956 else if (op->value == 1)
957 fprintf(output, "PLUS +");
958 else if (op->value == 2)
959 fprintf(output, "PLUS unary -");
960 else if (op->value == 3)
961 fprintf(output, "PLUS unary - -");
962 break;
963 case XPATH_OP_MULT:
964 if (op->value == 0)
965 fprintf(output, "MULT *");
966 else if (op->value == 1)
967 fprintf(output, "MULT div");
968 else
969 fprintf(output, "MULT mod");
970 break;
971 case XPATH_OP_UNION:
972 fprintf(output, "UNION"); break;
973 case XPATH_OP_ROOT:
974 fprintf(output, "ROOT"); break;
975 case XPATH_OP_NODE:
976 fprintf(output, "NODE"); break;
977 case XPATH_OP_RESET:
978 fprintf(output, "RESET"); break;
979 case XPATH_OP_SORT:
980 fprintf(output, "SORT"); break;
981 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000982 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
983 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
984 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000985 const xmlChar *prefix = op->value4;
986 const xmlChar *name = op->value5;
987
988 fprintf(output, "COLLECT ");
989 switch (axis) {
990 case AXIS_ANCESTOR:
991 fprintf(output, " 'ancestors' "); break;
992 case AXIS_ANCESTOR_OR_SELF:
993 fprintf(output, " 'ancestors-or-self' "); break;
994 case AXIS_ATTRIBUTE:
995 fprintf(output, " 'attributes' "); break;
996 case AXIS_CHILD:
997 fprintf(output, " 'child' "); break;
998 case AXIS_DESCENDANT:
999 fprintf(output, " 'descendant' "); break;
1000 case AXIS_DESCENDANT_OR_SELF:
1001 fprintf(output, " 'descendant-or-self' "); break;
1002 case AXIS_FOLLOWING:
1003 fprintf(output, " 'following' "); break;
1004 case AXIS_FOLLOWING_SIBLING:
1005 fprintf(output, " 'following-siblings' "); break;
1006 case AXIS_NAMESPACE:
1007 fprintf(output, " 'namespace' "); break;
1008 case AXIS_PARENT:
1009 fprintf(output, " 'parent' "); break;
1010 case AXIS_PRECEDING:
1011 fprintf(output, " 'preceding' "); break;
1012 case AXIS_PRECEDING_SIBLING:
1013 fprintf(output, " 'preceding-sibling' "); break;
1014 case AXIS_SELF:
1015 fprintf(output, " 'self' "); break;
1016 }
1017 switch (test) {
1018 case NODE_TEST_NONE:
1019 fprintf(output, "'none' "); break;
1020 case NODE_TEST_TYPE:
1021 fprintf(output, "'type' "); break;
1022 case NODE_TEST_PI:
1023 fprintf(output, "'PI' "); break;
1024 case NODE_TEST_ALL:
1025 fprintf(output, "'all' "); break;
1026 case NODE_TEST_NS:
1027 fprintf(output, "'namespace' "); break;
1028 case NODE_TEST_NAME:
1029 fprintf(output, "'name' "); break;
1030 }
1031 switch (type) {
1032 case NODE_TYPE_NODE:
1033 fprintf(output, "'node' "); break;
1034 case NODE_TYPE_COMMENT:
1035 fprintf(output, "'comment' "); break;
1036 case NODE_TYPE_TEXT:
1037 fprintf(output, "'text' "); break;
1038 case NODE_TYPE_PI:
1039 fprintf(output, "'PI' "); break;
1040 }
1041 if (prefix != NULL)
1042 fprintf(output, "%s:", prefix);
1043 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001044 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001045 break;
1046
1047 }
1048 case XPATH_OP_VALUE: {
1049 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1050
1051 fprintf(output, "ELEM ");
1052 xmlXPathDebugDumpObject(output, object, 0);
1053 goto finish;
1054 }
1055 case XPATH_OP_VARIABLE: {
1056 const xmlChar *prefix = op->value5;
1057 const xmlChar *name = op->value4;
1058
1059 if (prefix != NULL)
1060 fprintf(output, "VARIABLE %s:%s", prefix, name);
1061 else
1062 fprintf(output, "VARIABLE %s", name);
1063 break;
1064 }
1065 case XPATH_OP_FUNCTION: {
1066 int nbargs = op->value;
1067 const xmlChar *prefix = op->value5;
1068 const xmlChar *name = op->value4;
1069
1070 if (prefix != NULL)
1071 fprintf(output, "FUNCTION %s:%s(%d args)",
1072 prefix, name, nbargs);
1073 else
1074 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1075 break;
1076 }
1077 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1078 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001079 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001080#ifdef LIBXML_XPTR_ENABLED
1081 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1082#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001083 default:
1084 fprintf(output, "UNKNOWN %d\n", op->op); return;
1085 }
1086 fprintf(output, "\n");
1087finish:
1088 if (op->ch1 >= 0)
1089 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1090 if (op->ch2 >= 0)
1091 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1092}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001093
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001094/**
1095 * xmlXPathDebugDumpCompExpr:
1096 * @output: the FILE * for the output
1097 * @comp: the precompiled XPath expression
1098 * @depth: the indentation level.
1099 *
1100 * Dumps the tree of the compiled XPath expression.
1101 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001102void
1103xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1104 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001105 int i;
1106 char shift[100];
1107
Daniel Veillarda82b1822004-11-08 16:24:57 +00001108 if ((output == NULL) || (comp == NULL)) return;
1109
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001110 for (i = 0;((i < depth) && (i < 25));i++)
1111 shift[2 * i] = shift[2 * i + 1] = ' ';
1112 shift[2 * i] = shift[2 * i + 1] = 0;
1113
1114 fprintf(output, shift);
1115
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001116 fprintf(output, "Compiled Expression : %d elements\n",
1117 comp->nbStep);
1118 i = comp->last;
1119 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1120}
Daniel Veillard017b1082001-06-21 11:20:21 +00001121#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001122
1123/************************************************************************
1124 * *
1125 * Parser stacks related functions and macros *
1126 * *
1127 ************************************************************************/
1128
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001129/**
1130 * valuePop:
1131 * @ctxt: an XPath evaluation context
1132 *
1133 * Pops the top XPath object from the value stack
1134 *
1135 * Returns the XPath object just removed
1136 */
Daniel Veillard24505b02005-07-28 23:49:35 +00001137xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00001138valuePop(xmlXPathParserContextPtr ctxt)
1139{
1140 xmlXPathObjectPtr ret;
1141
Daniel Veillarda82b1822004-11-08 16:24:57 +00001142 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00001143 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +00001144 ctxt->valueNr--;
1145 if (ctxt->valueNr > 0)
1146 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1147 else
1148 ctxt->value = NULL;
1149 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00001150 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00001151 return (ret);
1152}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001153/**
1154 * valuePush:
1155 * @ctxt: an XPath evaluation context
1156 * @value: the XPath object
1157 *
1158 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001159 *
1160 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001161 */
Daniel Veillard24505b02005-07-28 23:49:35 +00001162int
Daniel Veillard1c732d22002-11-30 11:22:59 +00001163valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1164{
Daniel Veillarda82b1822004-11-08 16:24:57 +00001165 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00001166 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001167 xmlXPathObjectPtr *tmp;
1168
1169 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1170 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00001171 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001172 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00001173 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1174 return (0);
1175 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001176 ctxt->valueMax *= 2;
1177 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00001178 }
1179 ctxt->valueTab[ctxt->valueNr] = value;
1180 ctxt->value = value;
1181 return (ctxt->valueNr++);
1182}
Owen Taylor3473f882001-02-23 17:55:21 +00001183
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001184/**
1185 * xmlXPathPopBoolean:
1186 * @ctxt: an XPath parser context
1187 *
1188 * Pops a boolean from the stack, handling conversion if needed.
1189 * Check error with #xmlXPathCheckError.
1190 *
1191 * Returns the boolean
1192 */
1193int
1194xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1195 xmlXPathObjectPtr obj;
1196 int ret;
1197
1198 obj = valuePop(ctxt);
1199 if (obj == NULL) {
1200 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1201 return(0);
1202 }
William M. Brack08171912003-12-29 02:52:11 +00001203 if (obj->type != XPATH_BOOLEAN)
1204 ret = xmlXPathCastToBoolean(obj);
1205 else
1206 ret = obj->boolval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001207 xmlXPathFreeObject(obj);
1208 return(ret);
1209}
1210
1211/**
1212 * xmlXPathPopNumber:
1213 * @ctxt: an XPath parser context
1214 *
1215 * Pops a number from the stack, handling conversion if needed.
1216 * Check error with #xmlXPathCheckError.
1217 *
1218 * Returns the number
1219 */
1220double
1221xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1222 xmlXPathObjectPtr obj;
1223 double ret;
1224
1225 obj = valuePop(ctxt);
1226 if (obj == NULL) {
1227 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1228 return(0);
1229 }
William M. Brack08171912003-12-29 02:52:11 +00001230 if (obj->type != XPATH_NUMBER)
1231 ret = xmlXPathCastToNumber(obj);
1232 else
1233 ret = obj->floatval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001234 xmlXPathFreeObject(obj);
1235 return(ret);
1236}
1237
1238/**
1239 * xmlXPathPopString:
1240 * @ctxt: an XPath parser context
1241 *
1242 * Pops a string from the stack, handling conversion if needed.
1243 * Check error with #xmlXPathCheckError.
1244 *
1245 * Returns the string
1246 */
1247xmlChar *
1248xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1249 xmlXPathObjectPtr obj;
1250 xmlChar * ret;
1251
1252 obj = valuePop(ctxt);
1253 if (obj == NULL) {
1254 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1255 return(NULL);
1256 }
William M. Brack08171912003-12-29 02:52:11 +00001257 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001258 /* TODO: needs refactoring somewhere else */
1259 if (obj->stringval == ret)
1260 obj->stringval = NULL;
1261 xmlXPathFreeObject(obj);
1262 return(ret);
1263}
1264
1265/**
1266 * xmlXPathPopNodeSet:
1267 * @ctxt: an XPath parser context
1268 *
1269 * Pops a node-set from the stack, handling conversion if needed.
1270 * Check error with #xmlXPathCheckError.
1271 *
1272 * Returns the node-set
1273 */
1274xmlNodeSetPtr
1275xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1276 xmlXPathObjectPtr obj;
1277 xmlNodeSetPtr ret;
1278
Daniel Veillardf2a36f92004-11-08 17:55:01 +00001279 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001280 if (ctxt->value == NULL) {
1281 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1282 return(NULL);
1283 }
1284 if (!xmlXPathStackIsNodeSet(ctxt)) {
1285 xmlXPathSetTypeError(ctxt);
1286 return(NULL);
1287 }
1288 obj = valuePop(ctxt);
1289 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00001290#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00001291 /* to fix memory leak of not clearing obj->user */
1292 if (obj->boolval && obj->user != NULL)
1293 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00001294#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001295 xmlXPathFreeNodeSetList(obj);
1296 return(ret);
1297}
1298
1299/**
1300 * xmlXPathPopExternal:
1301 * @ctxt: an XPath parser context
1302 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001303 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001304 * Check error with #xmlXPathCheckError.
1305 *
1306 * Returns the object
1307 */
1308void *
1309xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1310 xmlXPathObjectPtr obj;
1311 void * ret;
1312
Daniel Veillarda82b1822004-11-08 16:24:57 +00001313 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001314 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1315 return(NULL);
1316 }
1317 if (ctxt->value->type != XPATH_USERS) {
1318 xmlXPathSetTypeError(ctxt);
1319 return(NULL);
1320 }
1321 obj = valuePop(ctxt);
1322 ret = obj->user;
1323 xmlXPathFreeObject(obj);
1324 return(ret);
1325}
1326
Owen Taylor3473f882001-02-23 17:55:21 +00001327/*
1328 * Macros for accessing the content. Those should be used only by the parser,
1329 * and not exported.
1330 *
1331 * Dirty macros, i.e. one need to make assumption on the context to use them
1332 *
1333 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1334 * CUR returns the current xmlChar value, i.e. a 8 bit value
1335 * in ISO-Latin or UTF-8.
1336 * This should be used internally by the parser
1337 * only to compare to ASCII values otherwise it would break when
1338 * running with UTF-8 encoding.
1339 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1340 * to compare on ASCII based substring.
1341 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1342 * strings within the parser.
1343 * CURRENT Returns the current char value, with the full decoding of
1344 * UTF-8 if we are using this mode. It returns an int.
1345 * NEXT Skip to the next character, this does the proper decoding
1346 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1347 * It returns the pointer to the current xmlChar.
1348 */
1349
1350#define CUR (*ctxt->cur)
1351#define SKIP(val) ctxt->cur += (val)
1352#define NXT(val) ctxt->cur[(val)]
1353#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001354#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1355
1356#define COPY_BUF(l,b,i,v) \
1357 if (l == 1) b[i++] = (xmlChar) v; \
1358 else i += xmlCopyChar(l,&b[i],v)
1359
1360#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001361
1362#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001363 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001364
1365#define CURRENT (*ctxt->cur)
1366#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1367
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001368
1369#ifndef DBL_DIG
1370#define DBL_DIG 16
1371#endif
1372#ifndef DBL_EPSILON
1373#define DBL_EPSILON 1E-9
1374#endif
1375
1376#define UPPER_DOUBLE 1E9
1377#define LOWER_DOUBLE 1E-5
1378
1379#define INTEGER_DIGITS DBL_DIG
1380#define FRACTION_DIGITS (DBL_DIG + 1)
1381#define EXPONENT_DIGITS (3 + 2)
1382
1383/**
1384 * xmlXPathFormatNumber:
1385 * @number: number to format
1386 * @buffer: output buffer
1387 * @buffersize: size of output buffer
1388 *
1389 * Convert the number into a string representation.
1390 */
1391static void
1392xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1393{
Daniel Veillardcda96922001-08-21 10:56:31 +00001394 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001395 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001396 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001397 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001398 break;
1399 case -1:
1400 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001401 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001402 break;
1403 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001404 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001405 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001406 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001407 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001408 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001409 } else if (number == ((int) number)) {
1410 char work[30];
1411 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00001412 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001413
1414 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001415 if (value == 0) {
1416 *ptr++ = '0';
1417 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00001418 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001419 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00001420 while ((*cur) && (ptr - buffer < buffersize)) {
1421 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001422 }
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;
Daniel Veillard11ce4002006-03-10 00:36:23 +00001452 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00001453 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00001454 while ((size > 0) && (work[size] != 'e')) size--;
1455 after_fraction = work + size;
1456
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001457 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001458 else {
1459 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001460 if (absolute_value > 0.0)
1461 integer_place = 1 + (int)log10(absolute_value);
1462 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001463 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001464 fraction_place = (integer_place > 0)
1465 ? DBL_DIG - integer_place
1466 : DBL_DIG;
1467 size = snprintf(work, sizeof(work), "%0.*f",
1468 fraction_place, number);
1469 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001470 }
1471
Bjorn Reese70a9da52001-04-21 16:57:29 +00001472 /* Remove fractional trailing zeroes */
1473 ptr = after_fraction;
1474 while (*(--ptr) == '0')
1475 ;
1476 if (*ptr != '.')
1477 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001478 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001479
1480 /* Finally copy result back to caller */
1481 size = strlen(work) + 1;
1482 if (size > buffersize) {
1483 work[buffersize - 1] = 0;
1484 size = buffersize;
1485 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001486 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001487 }
1488 break;
1489 }
1490}
1491
Owen Taylor3473f882001-02-23 17:55:21 +00001492
1493/************************************************************************
1494 * *
1495 * Routines to handle NodeSets *
1496 * *
1497 ************************************************************************/
1498
1499/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001500 * xmlXPathOrderDocElems:
1501 * @doc: an input document
1502 *
1503 * Call this routine to speed up XPath computation on static documents.
1504 * This stamps all the element nodes with the document order
1505 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00001506 * field, the value stored is actually - the node number (starting at -1)
1507 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001508 *
William M. Brack08171912003-12-29 02:52:11 +00001509 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001510 * of error.
1511 */
1512long
1513xmlXPathOrderDocElems(xmlDocPtr doc) {
1514 long count = 0;
1515 xmlNodePtr cur;
1516
1517 if (doc == NULL)
1518 return(-1);
1519 cur = doc->children;
1520 while (cur != NULL) {
1521 if (cur->type == XML_ELEMENT_NODE) {
1522 cur->content = (void *) (-(++count));
1523 if (cur->children != NULL) {
1524 cur = cur->children;
1525 continue;
1526 }
1527 }
1528 if (cur->next != NULL) {
1529 cur = cur->next;
1530 continue;
1531 }
1532 do {
1533 cur = cur->parent;
1534 if (cur == NULL)
1535 break;
1536 if (cur == (xmlNodePtr) doc) {
1537 cur = NULL;
1538 break;
1539 }
1540 if (cur->next != NULL) {
1541 cur = cur->next;
1542 break;
1543 }
1544 } while (cur != NULL);
1545 }
1546 return(count);
1547}
1548
1549/**
Owen Taylor3473f882001-02-23 17:55:21 +00001550 * xmlXPathCmpNodes:
1551 * @node1: the first node
1552 * @node2: the second node
1553 *
1554 * Compare two nodes w.r.t document order
1555 *
1556 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00001557 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001558 */
1559int
1560xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1561 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001562 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001563 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001564 xmlNodePtr cur, root;
1565
1566 if ((node1 == NULL) || (node2 == NULL))
1567 return(-2);
1568 /*
1569 * a couple of optimizations which will avoid computations in most cases
1570 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001571 if (node1->type == XML_ATTRIBUTE_NODE) {
1572 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001573 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001574 node1 = node1->parent;
1575 }
1576 if (node2->type == XML_ATTRIBUTE_NODE) {
1577 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001578 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001579 node2 = node2->parent;
1580 }
1581 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001582 if (attr1 == attr2) {
1583 /* not required, but we keep attributes in order */
1584 if (attr1 != 0) {
1585 cur = attrNode2->prev;
1586 while (cur != NULL) {
1587 if (cur == attrNode1)
1588 return (1);
1589 cur = cur->prev;
1590 }
1591 return (-1);
1592 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001593 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001594 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001595 if (attr2 == 1)
1596 return(1);
1597 return(-1);
1598 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001599 if ((node1->type == XML_NAMESPACE_DECL) ||
1600 (node2->type == XML_NAMESPACE_DECL))
1601 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001602 if (node1 == node2->prev)
1603 return(1);
1604 if (node1 == node2->next)
1605 return(-1);
1606
1607 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001608 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001609 */
1610 if ((node1->type == XML_ELEMENT_NODE) &&
1611 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001612 (0 > (long) node1->content) &&
1613 (0 > (long) node2->content) &&
1614 (node1->doc == node2->doc)) {
1615 long l1, l2;
1616
1617 l1 = -((long) node1->content);
1618 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001619 if (l1 < l2)
1620 return(1);
1621 if (l1 > l2)
1622 return(-1);
1623 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001624
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001625 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001626 * compute depth to root
1627 */
1628 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1629 if (cur == node1)
1630 return(1);
1631 depth2++;
1632 }
1633 root = cur;
1634 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1635 if (cur == node2)
1636 return(-1);
1637 depth1++;
1638 }
1639 /*
1640 * Distinct document (or distinct entities :-( ) case.
1641 */
1642 if (root != cur) {
1643 return(-2);
1644 }
1645 /*
1646 * get the nearest common ancestor.
1647 */
1648 while (depth1 > depth2) {
1649 depth1--;
1650 node1 = node1->parent;
1651 }
1652 while (depth2 > depth1) {
1653 depth2--;
1654 node2 = node2->parent;
1655 }
1656 while (node1->parent != node2->parent) {
1657 node1 = node1->parent;
1658 node2 = node2->parent;
1659 /* should not happen but just in case ... */
1660 if ((node1 == NULL) || (node2 == NULL))
1661 return(-2);
1662 }
1663 /*
1664 * Find who's first.
1665 */
Daniel Veillardf49be472004-02-17 11:48:18 +00001666 if (node1 == node2->prev)
1667 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001668 if (node1 == node2->next)
1669 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00001670 /*
1671 * Speedup using document order if availble.
1672 */
1673 if ((node1->type == XML_ELEMENT_NODE) &&
1674 (node2->type == XML_ELEMENT_NODE) &&
1675 (0 > (long) node1->content) &&
1676 (0 > (long) node2->content) &&
1677 (node1->doc == node2->doc)) {
1678 long l1, l2;
1679
1680 l1 = -((long) node1->content);
1681 l2 = -((long) node2->content);
1682 if (l1 < l2)
1683 return(1);
1684 if (l1 > l2)
1685 return(-1);
1686 }
1687
Owen Taylor3473f882001-02-23 17:55:21 +00001688 for (cur = node1->next;cur != NULL;cur = cur->next)
1689 if (cur == node2)
1690 return(1);
1691 return(-1); /* assume there is no sibling list corruption */
1692}
1693
1694/**
1695 * xmlXPathNodeSetSort:
1696 * @set: the node set
1697 *
1698 * Sort the node set in document order
1699 */
1700void
1701xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001702 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001703 xmlNodePtr tmp;
1704
1705 if (set == NULL)
1706 return;
1707
1708 /* Use Shell's sort to sort the node-set */
1709 len = set->nodeNr;
1710 for (incr = len / 2; incr > 0; incr /= 2) {
1711 for (i = incr; i < len; i++) {
1712 j = i - incr;
1713 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001714 if (xmlXPathCmpNodes(set->nodeTab[j],
1715 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001716 tmp = set->nodeTab[j];
1717 set->nodeTab[j] = set->nodeTab[j + incr];
1718 set->nodeTab[j + incr] = tmp;
1719 j -= incr;
1720 } else
1721 break;
1722 }
1723 }
1724 }
1725}
1726
1727#define XML_NODESET_DEFAULT 10
1728/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001729 * xmlXPathNodeSetDupNs:
1730 * @node: the parent node of the namespace XPath node
1731 * @ns: the libxml namespace declaration node.
1732 *
1733 * Namespace node in libxml don't match the XPath semantic. In a node set
1734 * the namespace nodes are duplicated and the next pointer is set to the
1735 * parent node in the XPath semantic.
1736 *
1737 * Returns the newly created object.
1738 */
1739static xmlNodePtr
1740xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1741 xmlNsPtr cur;
1742
1743 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1744 return(NULL);
1745 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1746 return((xmlNodePtr) ns);
1747
1748 /*
1749 * Allocate a new Namespace and fill the fields.
1750 */
1751 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1752 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001753 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001754 return(NULL);
1755 }
1756 memset(cur, 0, sizeof(xmlNs));
1757 cur->type = XML_NAMESPACE_DECL;
1758 if (ns->href != NULL)
1759 cur->href = xmlStrdup(ns->href);
1760 if (ns->prefix != NULL)
1761 cur->prefix = xmlStrdup(ns->prefix);
1762 cur->next = (xmlNsPtr) node;
1763 return((xmlNodePtr) cur);
1764}
1765
1766/**
1767 * xmlXPathNodeSetFreeNs:
1768 * @ns: the XPath namespace node found in a nodeset.
1769 *
William M. Brack08171912003-12-29 02:52:11 +00001770 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001771 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00001772 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001773 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001774void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001775xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1776 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1777 return;
1778
1779 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1780 if (ns->href != NULL)
1781 xmlFree((xmlChar *)ns->href);
1782 if (ns->prefix != NULL)
1783 xmlFree((xmlChar *)ns->prefix);
1784 xmlFree(ns);
1785 }
1786}
1787
1788/**
Owen Taylor3473f882001-02-23 17:55:21 +00001789 * xmlXPathNodeSetCreate:
1790 * @val: an initial xmlNodePtr, or NULL
1791 *
1792 * Create a new xmlNodeSetPtr of type double and of value @val
1793 *
1794 * Returns the newly created object.
1795 */
1796xmlNodeSetPtr
1797xmlXPathNodeSetCreate(xmlNodePtr val) {
1798 xmlNodeSetPtr ret;
1799
1800 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1801 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001802 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001803 return(NULL);
1804 }
1805 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1806 if (val != NULL) {
1807 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1808 sizeof(xmlNodePtr));
1809 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001810 xmlXPathErrMemory(NULL, "creating nodeset\n");
1811 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001812 return(NULL);
1813 }
1814 memset(ret->nodeTab, 0 ,
1815 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1816 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001817 if (val->type == XML_NAMESPACE_DECL) {
1818 xmlNsPtr ns = (xmlNsPtr) val;
1819
1820 ret->nodeTab[ret->nodeNr++] =
1821 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1822 } else
1823 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001824 }
1825 return(ret);
1826}
1827
1828/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001829 * xmlXPathNodeSetContains:
1830 * @cur: the node-set
1831 * @val: the node
1832 *
1833 * checks whether @cur contains @val
1834 *
1835 * Returns true (1) if @cur contains @val, false (0) otherwise
1836 */
1837int
1838xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1839 int i;
1840
Daniel Veillarda82b1822004-11-08 16:24:57 +00001841 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001842 if (val->type == XML_NAMESPACE_DECL) {
1843 for (i = 0; i < cur->nodeNr; i++) {
1844 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1845 xmlNsPtr ns1, ns2;
1846
1847 ns1 = (xmlNsPtr) val;
1848 ns2 = (xmlNsPtr) cur->nodeTab[i];
1849 if (ns1 == ns2)
1850 return(1);
1851 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1852 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1853 return(1);
1854 }
1855 }
1856 } else {
1857 for (i = 0; i < cur->nodeNr; i++) {
1858 if (cur->nodeTab[i] == val)
1859 return(1);
1860 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001861 }
1862 return(0);
1863}
1864
1865/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001866 * xmlXPathNodeSetAddNs:
1867 * @cur: the initial node set
1868 * @node: the hosting node
1869 * @ns: a the namespace node
1870 *
1871 * add a new namespace node to an existing NodeSet
1872 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001873void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001874xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1875 int i;
1876
Daniel Veillarda82b1822004-11-08 16:24:57 +00001877
1878 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
1879 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001880 (node->type != XML_ELEMENT_NODE))
1881 return;
1882
William M. Brack08171912003-12-29 02:52:11 +00001883 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001884 /*
William M. Brack08171912003-12-29 02:52:11 +00001885 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001886 */
1887 for (i = 0;i < cur->nodeNr;i++) {
1888 if ((cur->nodeTab[i] != NULL) &&
1889 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001890 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001891 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1892 return;
1893 }
1894
1895 /*
1896 * grow the nodeTab if needed
1897 */
1898 if (cur->nodeMax == 0) {
1899 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1900 sizeof(xmlNodePtr));
1901 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001902 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001903 return;
1904 }
1905 memset(cur->nodeTab, 0 ,
1906 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1907 cur->nodeMax = XML_NODESET_DEFAULT;
1908 } else if (cur->nodeNr == cur->nodeMax) {
1909 xmlNodePtr *temp;
1910
1911 cur->nodeMax *= 2;
1912 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1913 sizeof(xmlNodePtr));
1914 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001915 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001916 return;
1917 }
1918 cur->nodeTab = temp;
1919 }
1920 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1921}
1922
1923/**
Owen Taylor3473f882001-02-23 17:55:21 +00001924 * xmlXPathNodeSetAdd:
1925 * @cur: the initial node set
1926 * @val: a new xmlNodePtr
1927 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001928 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001929 */
1930void
1931xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1932 int i;
1933
Daniel Veillarda82b1822004-11-08 16:24:57 +00001934 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001935
Daniel Veillardef0b4502003-03-24 13:57:34 +00001936#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001937 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1938 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001939#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001940
William M. Brack08171912003-12-29 02:52:11 +00001941 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001942 /*
William M. Brack08171912003-12-29 02:52:11 +00001943 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00001944 */
1945 for (i = 0;i < cur->nodeNr;i++)
1946 if (cur->nodeTab[i] == val) return;
1947
1948 /*
1949 * grow the nodeTab if needed
1950 */
1951 if (cur->nodeMax == 0) {
1952 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1953 sizeof(xmlNodePtr));
1954 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001955 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001956 return;
1957 }
1958 memset(cur->nodeTab, 0 ,
1959 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1960 cur->nodeMax = XML_NODESET_DEFAULT;
1961 } else if (cur->nodeNr == cur->nodeMax) {
1962 xmlNodePtr *temp;
1963
1964 cur->nodeMax *= 2;
1965 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1966 sizeof(xmlNodePtr));
1967 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001968 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001969 return;
1970 }
1971 cur->nodeTab = temp;
1972 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001973 if (val->type == XML_NAMESPACE_DECL) {
1974 xmlNsPtr ns = (xmlNsPtr) val;
1975
1976 cur->nodeTab[cur->nodeNr++] =
1977 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1978 } else
1979 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001980}
1981
1982/**
1983 * xmlXPathNodeSetAddUnique:
1984 * @cur: the initial node set
1985 * @val: a new xmlNodePtr
1986 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001987 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001988 * when we are sure the node is not already in the set.
1989 */
1990void
1991xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00001992 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001993
Daniel Veillardef0b4502003-03-24 13:57:34 +00001994#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001995 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1996 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001997#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001998
William M. Brack08171912003-12-29 02:52:11 +00001999 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002000 /*
2001 * grow the nodeTab if needed
2002 */
2003 if (cur->nodeMax == 0) {
2004 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2005 sizeof(xmlNodePtr));
2006 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002007 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002008 return;
2009 }
2010 memset(cur->nodeTab, 0 ,
2011 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2012 cur->nodeMax = XML_NODESET_DEFAULT;
2013 } else if (cur->nodeNr == cur->nodeMax) {
2014 xmlNodePtr *temp;
2015
2016 cur->nodeMax *= 2;
2017 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
2018 sizeof(xmlNodePtr));
2019 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002020 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002021 return;
2022 }
2023 cur->nodeTab = temp;
2024 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002025 if (val->type == XML_NAMESPACE_DECL) {
2026 xmlNsPtr ns = (xmlNsPtr) val;
2027
2028 cur->nodeTab[cur->nodeNr++] =
2029 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2030 } else
2031 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00002032}
2033
2034/**
2035 * xmlXPathNodeSetMerge:
2036 * @val1: the first NodeSet or NULL
2037 * @val2: the second NodeSet
2038 *
2039 * Merges two nodesets, all nodes from @val2 are added to @val1
2040 * if @val1 is NULL, a new set is created and copied from @val2
2041 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002042 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002043 */
2044xmlNodeSetPtr
2045xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002046 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00002047
2048 if (val2 == NULL) return(val1);
2049 if (val1 == NULL) {
2050 val1 = xmlXPathNodeSetCreate(NULL);
2051 }
2052
William M. Brack08171912003-12-29 02:52:11 +00002053 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002054 initNr = val1->nodeNr;
2055
2056 for (i = 0;i < val2->nodeNr;i++) {
2057 /*
William M. Brack08171912003-12-29 02:52:11 +00002058 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00002059 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002060 skip = 0;
2061 for (j = 0; j < initNr; j++) {
2062 if (val1->nodeTab[j] == val2->nodeTab[i]) {
2063 skip = 1;
2064 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002065 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
2066 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
2067 xmlNsPtr ns1, ns2;
2068 ns1 = (xmlNsPtr) val1->nodeTab[j];
2069 ns2 = (xmlNsPtr) val2->nodeTab[i];
2070 if ((ns1->next == ns2->next) &&
2071 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
2072 skip = 1;
2073 break;
2074 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002075 }
2076 }
2077 if (skip)
2078 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00002079
2080 /*
2081 * grow the nodeTab if needed
2082 */
2083 if (val1->nodeMax == 0) {
2084 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2085 sizeof(xmlNodePtr));
2086 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002087 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002088 return(NULL);
2089 }
2090 memset(val1->nodeTab, 0 ,
2091 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2092 val1->nodeMax = XML_NODESET_DEFAULT;
2093 } else if (val1->nodeNr == val1->nodeMax) {
2094 xmlNodePtr *temp;
2095
2096 val1->nodeMax *= 2;
2097 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2098 sizeof(xmlNodePtr));
2099 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002100 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002101 return(NULL);
2102 }
2103 val1->nodeTab = temp;
2104 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002105 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2106 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2107
2108 val1->nodeTab[val1->nodeNr++] =
2109 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2110 } else
2111 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002112 }
2113
2114 return(val1);
2115}
2116
2117/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002118 * xmlXPathNodeSetMergeUnique:
2119 * @val1: the first NodeSet or NULL
2120 * @val2: the second NodeSet
2121 *
2122 * Merges two nodesets, all nodes from @val2 are added to @val1
2123 * if @val1 is NULL, a new set is created and copied from @val2
2124 *
2125 * Returns @val1 once extended or NULL in case of error.
2126 */
2127static xmlNodeSetPtr
2128xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002129 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002130
2131 if (val2 == NULL) return(val1);
2132 if (val1 == NULL) {
2133 val1 = xmlXPathNodeSetCreate(NULL);
2134 }
2135
William M. Brack08171912003-12-29 02:52:11 +00002136 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002137
2138 for (i = 0;i < val2->nodeNr;i++) {
2139 /*
2140 * grow the nodeTab if needed
2141 */
2142 if (val1->nodeMax == 0) {
2143 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2144 sizeof(xmlNodePtr));
2145 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002146 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002147 return(NULL);
2148 }
2149 memset(val1->nodeTab, 0 ,
2150 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2151 val1->nodeMax = XML_NODESET_DEFAULT;
2152 } else if (val1->nodeNr == val1->nodeMax) {
2153 xmlNodePtr *temp;
2154
2155 val1->nodeMax *= 2;
2156 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2157 sizeof(xmlNodePtr));
2158 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002159 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002160 return(NULL);
2161 }
2162 val1->nodeTab = temp;
2163 }
2164 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2165 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2166
2167 val1->nodeTab[val1->nodeNr++] =
2168 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2169 } else
2170 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2171 }
2172
2173 return(val1);
2174}
2175
2176/**
Owen Taylor3473f882001-02-23 17:55:21 +00002177 * xmlXPathNodeSetDel:
2178 * @cur: the initial node set
2179 * @val: an xmlNodePtr
2180 *
2181 * Removes an xmlNodePtr from an existing NodeSet
2182 */
2183void
2184xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2185 int i;
2186
2187 if (cur == NULL) return;
2188 if (val == NULL) return;
2189
2190 /*
William M. Brack08171912003-12-29 02:52:11 +00002191 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002192 */
2193 for (i = 0;i < cur->nodeNr;i++)
2194 if (cur->nodeTab[i] == val) break;
2195
William M. Brack08171912003-12-29 02:52:11 +00002196 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002197#ifdef DEBUG
2198 xmlGenericError(xmlGenericErrorContext,
2199 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2200 val->name);
2201#endif
2202 return;
2203 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002204 if ((cur->nodeTab[i] != NULL) &&
2205 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2206 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002207 cur->nodeNr--;
2208 for (;i < cur->nodeNr;i++)
2209 cur->nodeTab[i] = cur->nodeTab[i + 1];
2210 cur->nodeTab[cur->nodeNr] = NULL;
2211}
2212
2213/**
2214 * xmlXPathNodeSetRemove:
2215 * @cur: the initial node set
2216 * @val: the index to remove
2217 *
2218 * Removes an entry from an existing NodeSet list.
2219 */
2220void
2221xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2222 if (cur == NULL) return;
2223 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002224 if ((cur->nodeTab[val] != NULL) &&
2225 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2226 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002227 cur->nodeNr--;
2228 for (;val < cur->nodeNr;val++)
2229 cur->nodeTab[val] = cur->nodeTab[val + 1];
2230 cur->nodeTab[cur->nodeNr] = NULL;
2231}
2232
2233/**
2234 * xmlXPathFreeNodeSet:
2235 * @obj: the xmlNodeSetPtr to free
2236 *
2237 * Free the NodeSet compound (not the actual nodes !).
2238 */
2239void
2240xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2241 if (obj == NULL) return;
2242 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002243 int i;
2244
William M. Brack08171912003-12-29 02:52:11 +00002245 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002246 for (i = 0;i < obj->nodeNr;i++)
2247 if ((obj->nodeTab[i] != NULL) &&
2248 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2249 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002250 xmlFree(obj->nodeTab);
2251 }
Owen Taylor3473f882001-02-23 17:55:21 +00002252 xmlFree(obj);
2253}
2254
2255/**
2256 * xmlXPathFreeValueTree:
2257 * @obj: the xmlNodeSetPtr to free
2258 *
2259 * Free the NodeSet compound and the actual tree, this is different
2260 * from xmlXPathFreeNodeSet()
2261 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002262static void
Owen Taylor3473f882001-02-23 17:55:21 +00002263xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2264 int i;
2265
2266 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002267
2268 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002269 for (i = 0;i < obj->nodeNr;i++) {
2270 if (obj->nodeTab[i] != NULL) {
2271 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2272 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2273 } else {
2274 xmlFreeNodeList(obj->nodeTab[i]);
2275 }
2276 }
2277 }
Owen Taylor3473f882001-02-23 17:55:21 +00002278 xmlFree(obj->nodeTab);
2279 }
Owen Taylor3473f882001-02-23 17:55:21 +00002280 xmlFree(obj);
2281}
2282
2283#if defined(DEBUG) || defined(DEBUG_STEP)
2284/**
2285 * xmlGenericErrorContextNodeSet:
2286 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002287 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002288 *
2289 * Quick display of a NodeSet
2290 */
2291void
2292xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2293 int i;
2294
2295 if (output == NULL) output = xmlGenericErrorContext;
2296 if (obj == NULL) {
2297 fprintf(output, "NodeSet == NULL !\n");
2298 return;
2299 }
2300 if (obj->nodeNr == 0) {
2301 fprintf(output, "NodeSet is empty\n");
2302 return;
2303 }
2304 if (obj->nodeTab == NULL) {
2305 fprintf(output, " nodeTab == NULL !\n");
2306 return;
2307 }
2308 for (i = 0; i < obj->nodeNr; i++) {
2309 if (obj->nodeTab[i] == NULL) {
2310 fprintf(output, " NULL !\n");
2311 return;
2312 }
2313 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2314 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2315 fprintf(output, " /");
2316 else if (obj->nodeTab[i]->name == NULL)
2317 fprintf(output, " noname!");
2318 else fprintf(output, " %s", obj->nodeTab[i]->name);
2319 }
2320 fprintf(output, "\n");
2321}
2322#endif
2323
2324/**
2325 * xmlXPathNewNodeSet:
2326 * @val: the NodePtr value
2327 *
2328 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2329 * it with the single Node @val
2330 *
2331 * Returns the newly created object.
2332 */
2333xmlXPathObjectPtr
2334xmlXPathNewNodeSet(xmlNodePtr val) {
2335 xmlXPathObjectPtr ret;
2336
2337 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2338 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002339 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002340 return(NULL);
2341 }
2342 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2343 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002344 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002345 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002346 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002347 return(ret);
2348}
2349
2350/**
2351 * xmlXPathNewValueTree:
2352 * @val: the NodePtr value
2353 *
2354 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2355 * it with the tree root @val
2356 *
2357 * Returns the newly created object.
2358 */
2359xmlXPathObjectPtr
2360xmlXPathNewValueTree(xmlNodePtr val) {
2361 xmlXPathObjectPtr ret;
2362
2363 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2364 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002365 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002366 return(NULL);
2367 }
2368 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2369 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002370 ret->boolval = 1;
2371 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002372 ret->nodesetval = xmlXPathNodeSetCreate(val);
2373 return(ret);
2374}
2375
2376/**
2377 * xmlXPathNewNodeSetList:
2378 * @val: an existing NodeSet
2379 *
2380 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2381 * it with the Nodeset @val
2382 *
2383 * Returns the newly created object.
2384 */
2385xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002386xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2387{
Owen Taylor3473f882001-02-23 17:55:21 +00002388 xmlXPathObjectPtr ret;
2389 int i;
2390
2391 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002392 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002393 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002394 ret = xmlXPathNewNodeSet(NULL);
2395 else {
2396 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2397 for (i = 1; i < val->nodeNr; ++i)
2398 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2399 }
Owen Taylor3473f882001-02-23 17:55:21 +00002400
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002401 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002402}
2403
2404/**
2405 * xmlXPathWrapNodeSet:
2406 * @val: the NodePtr value
2407 *
2408 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2409 *
2410 * Returns the newly created object.
2411 */
2412xmlXPathObjectPtr
2413xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2414 xmlXPathObjectPtr ret;
2415
2416 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2417 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002418 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002419 return(NULL);
2420 }
2421 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2422 ret->type = XPATH_NODESET;
2423 ret->nodesetval = val;
2424 return(ret);
2425}
2426
2427/**
2428 * xmlXPathFreeNodeSetList:
2429 * @obj: an existing NodeSetList object
2430 *
2431 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2432 * the list contrary to xmlXPathFreeObject().
2433 */
2434void
2435xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2436 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002437 xmlFree(obj);
2438}
2439
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002440/**
2441 * xmlXPathDifference:
2442 * @nodes1: a node-set
2443 * @nodes2: a node-set
2444 *
2445 * Implements the EXSLT - Sets difference() function:
2446 * node-set set:difference (node-set, node-set)
2447 *
2448 * Returns the difference between the two node sets, or nodes1 if
2449 * nodes2 is empty
2450 */
2451xmlNodeSetPtr
2452xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2453 xmlNodeSetPtr ret;
2454 int i, l1;
2455 xmlNodePtr cur;
2456
2457 if (xmlXPathNodeSetIsEmpty(nodes2))
2458 return(nodes1);
2459
2460 ret = xmlXPathNodeSetCreate(NULL);
2461 if (xmlXPathNodeSetIsEmpty(nodes1))
2462 return(ret);
2463
2464 l1 = xmlXPathNodeSetGetLength(nodes1);
2465
2466 for (i = 0; i < l1; i++) {
2467 cur = xmlXPathNodeSetItem(nodes1, i);
2468 if (!xmlXPathNodeSetContains(nodes2, cur))
2469 xmlXPathNodeSetAddUnique(ret, cur);
2470 }
2471 return(ret);
2472}
2473
2474/**
2475 * xmlXPathIntersection:
2476 * @nodes1: a node-set
2477 * @nodes2: a node-set
2478 *
2479 * Implements the EXSLT - Sets intersection() function:
2480 * node-set set:intersection (node-set, node-set)
2481 *
2482 * Returns a node set comprising the nodes that are within both the
2483 * node sets passed as arguments
2484 */
2485xmlNodeSetPtr
2486xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2487 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2488 int i, l1;
2489 xmlNodePtr cur;
2490
2491 if (xmlXPathNodeSetIsEmpty(nodes1))
2492 return(ret);
2493 if (xmlXPathNodeSetIsEmpty(nodes2))
2494 return(ret);
2495
2496 l1 = xmlXPathNodeSetGetLength(nodes1);
2497
2498 for (i = 0; i < l1; i++) {
2499 cur = xmlXPathNodeSetItem(nodes1, i);
2500 if (xmlXPathNodeSetContains(nodes2, cur))
2501 xmlXPathNodeSetAddUnique(ret, cur);
2502 }
2503 return(ret);
2504}
2505
2506/**
2507 * xmlXPathDistinctSorted:
2508 * @nodes: a node-set, sorted by document order
2509 *
2510 * Implements the EXSLT - Sets distinct() function:
2511 * node-set set:distinct (node-set)
2512 *
2513 * Returns a subset of the nodes contained in @nodes, or @nodes if
2514 * it is empty
2515 */
2516xmlNodeSetPtr
2517xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2518 xmlNodeSetPtr ret;
2519 xmlHashTablePtr hash;
2520 int i, l;
2521 xmlChar * strval;
2522 xmlNodePtr cur;
2523
2524 if (xmlXPathNodeSetIsEmpty(nodes))
2525 return(nodes);
2526
2527 ret = xmlXPathNodeSetCreate(NULL);
2528 l = xmlXPathNodeSetGetLength(nodes);
2529 hash = xmlHashCreate (l);
2530 for (i = 0; i < l; i++) {
2531 cur = xmlXPathNodeSetItem(nodes, i);
2532 strval = xmlXPathCastNodeToString(cur);
2533 if (xmlHashLookup(hash, strval) == NULL) {
2534 xmlHashAddEntry(hash, strval, strval);
2535 xmlXPathNodeSetAddUnique(ret, cur);
2536 } else {
2537 xmlFree(strval);
2538 }
2539 }
2540 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2541 return(ret);
2542}
2543
2544/**
2545 * xmlXPathDistinct:
2546 * @nodes: a node-set
2547 *
2548 * Implements the EXSLT - Sets distinct() function:
2549 * node-set set:distinct (node-set)
2550 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2551 * is called with the sorted node-set
2552 *
2553 * Returns a subset of the nodes contained in @nodes, or @nodes if
2554 * it is empty
2555 */
2556xmlNodeSetPtr
2557xmlXPathDistinct (xmlNodeSetPtr nodes) {
2558 if (xmlXPathNodeSetIsEmpty(nodes))
2559 return(nodes);
2560
2561 xmlXPathNodeSetSort(nodes);
2562 return(xmlXPathDistinctSorted(nodes));
2563}
2564
2565/**
2566 * xmlXPathHasSameNodes:
2567 * @nodes1: a node-set
2568 * @nodes2: a node-set
2569 *
2570 * Implements the EXSLT - Sets has-same-nodes function:
2571 * boolean set:has-same-node(node-set, node-set)
2572 *
2573 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2574 * otherwise
2575 */
2576int
2577xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2578 int i, l;
2579 xmlNodePtr cur;
2580
2581 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2582 xmlXPathNodeSetIsEmpty(nodes2))
2583 return(0);
2584
2585 l = xmlXPathNodeSetGetLength(nodes1);
2586 for (i = 0; i < l; i++) {
2587 cur = xmlXPathNodeSetItem(nodes1, i);
2588 if (xmlXPathNodeSetContains(nodes2, cur))
2589 return(1);
2590 }
2591 return(0);
2592}
2593
2594/**
2595 * xmlXPathNodeLeadingSorted:
2596 * @nodes: a node-set, sorted by document order
2597 * @node: a node
2598 *
2599 * Implements the EXSLT - Sets leading() function:
2600 * node-set set:leading (node-set, node-set)
2601 *
2602 * Returns the nodes in @nodes that precede @node in document order,
2603 * @nodes if @node is NULL or an empty node-set if @nodes
2604 * doesn't contain @node
2605 */
2606xmlNodeSetPtr
2607xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2608 int i, l;
2609 xmlNodePtr cur;
2610 xmlNodeSetPtr ret;
2611
2612 if (node == NULL)
2613 return(nodes);
2614
2615 ret = xmlXPathNodeSetCreate(NULL);
2616 if (xmlXPathNodeSetIsEmpty(nodes) ||
2617 (!xmlXPathNodeSetContains(nodes, node)))
2618 return(ret);
2619
2620 l = xmlXPathNodeSetGetLength(nodes);
2621 for (i = 0; i < l; i++) {
2622 cur = xmlXPathNodeSetItem(nodes, i);
2623 if (cur == node)
2624 break;
2625 xmlXPathNodeSetAddUnique(ret, cur);
2626 }
2627 return(ret);
2628}
2629
2630/**
2631 * xmlXPathNodeLeading:
2632 * @nodes: a node-set
2633 * @node: a node
2634 *
2635 * Implements the EXSLT - Sets leading() function:
2636 * node-set set:leading (node-set, node-set)
2637 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2638 * is called.
2639 *
2640 * Returns the nodes in @nodes that precede @node in document order,
2641 * @nodes if @node is NULL or an empty node-set if @nodes
2642 * doesn't contain @node
2643 */
2644xmlNodeSetPtr
2645xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2646 xmlXPathNodeSetSort(nodes);
2647 return(xmlXPathNodeLeadingSorted(nodes, node));
2648}
2649
2650/**
2651 * xmlXPathLeadingSorted:
2652 * @nodes1: a node-set, sorted by document order
2653 * @nodes2: a node-set, sorted by document order
2654 *
2655 * Implements the EXSLT - Sets leading() function:
2656 * node-set set:leading (node-set, node-set)
2657 *
2658 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2659 * in document order, @nodes1 if @nodes2 is NULL or empty or
2660 * an empty node-set if @nodes1 doesn't contain @nodes2
2661 */
2662xmlNodeSetPtr
2663xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2664 if (xmlXPathNodeSetIsEmpty(nodes2))
2665 return(nodes1);
2666 return(xmlXPathNodeLeadingSorted(nodes1,
2667 xmlXPathNodeSetItem(nodes2, 1)));
2668}
2669
2670/**
2671 * xmlXPathLeading:
2672 * @nodes1: a node-set
2673 * @nodes2: a node-set
2674 *
2675 * Implements the EXSLT - Sets leading() function:
2676 * node-set set:leading (node-set, node-set)
2677 * @nodes1 and @nodes2 are sorted by document order, then
2678 * #exslSetsLeadingSorted is called.
2679 *
2680 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2681 * in document order, @nodes1 if @nodes2 is NULL or empty or
2682 * an empty node-set if @nodes1 doesn't contain @nodes2
2683 */
2684xmlNodeSetPtr
2685xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2686 if (xmlXPathNodeSetIsEmpty(nodes2))
2687 return(nodes1);
2688 if (xmlXPathNodeSetIsEmpty(nodes1))
2689 return(xmlXPathNodeSetCreate(NULL));
2690 xmlXPathNodeSetSort(nodes1);
2691 xmlXPathNodeSetSort(nodes2);
2692 return(xmlXPathNodeLeadingSorted(nodes1,
2693 xmlXPathNodeSetItem(nodes2, 1)));
2694}
2695
2696/**
2697 * xmlXPathNodeTrailingSorted:
2698 * @nodes: a node-set, sorted by document order
2699 * @node: a node
2700 *
2701 * Implements the EXSLT - Sets trailing() function:
2702 * node-set set:trailing (node-set, node-set)
2703 *
2704 * Returns the nodes in @nodes that follow @node in document order,
2705 * @nodes if @node is NULL or an empty node-set if @nodes
2706 * doesn't contain @node
2707 */
2708xmlNodeSetPtr
2709xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2710 int i, l;
2711 xmlNodePtr cur;
2712 xmlNodeSetPtr ret;
2713
2714 if (node == NULL)
2715 return(nodes);
2716
2717 ret = xmlXPathNodeSetCreate(NULL);
2718 if (xmlXPathNodeSetIsEmpty(nodes) ||
2719 (!xmlXPathNodeSetContains(nodes, node)))
2720 return(ret);
2721
2722 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002723 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002724 cur = xmlXPathNodeSetItem(nodes, i);
2725 if (cur == node)
2726 break;
2727 xmlXPathNodeSetAddUnique(ret, cur);
2728 }
2729 return(ret);
2730}
2731
2732/**
2733 * xmlXPathNodeTrailing:
2734 * @nodes: a node-set
2735 * @node: a node
2736 *
2737 * Implements the EXSLT - Sets trailing() function:
2738 * node-set set:trailing (node-set, node-set)
2739 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2740 * is called.
2741 *
2742 * Returns the nodes in @nodes that follow @node in document order,
2743 * @nodes if @node is NULL or an empty node-set if @nodes
2744 * doesn't contain @node
2745 */
2746xmlNodeSetPtr
2747xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2748 xmlXPathNodeSetSort(nodes);
2749 return(xmlXPathNodeTrailingSorted(nodes, node));
2750}
2751
2752/**
2753 * xmlXPathTrailingSorted:
2754 * @nodes1: a node-set, sorted by document order
2755 * @nodes2: a node-set, sorted by document order
2756 *
2757 * Implements the EXSLT - Sets trailing() function:
2758 * node-set set:trailing (node-set, node-set)
2759 *
2760 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2761 * in document order, @nodes1 if @nodes2 is NULL or empty or
2762 * an empty node-set if @nodes1 doesn't contain @nodes2
2763 */
2764xmlNodeSetPtr
2765xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2766 if (xmlXPathNodeSetIsEmpty(nodes2))
2767 return(nodes1);
2768 return(xmlXPathNodeTrailingSorted(nodes1,
2769 xmlXPathNodeSetItem(nodes2, 0)));
2770}
2771
2772/**
2773 * xmlXPathTrailing:
2774 * @nodes1: a node-set
2775 * @nodes2: a node-set
2776 *
2777 * Implements the EXSLT - Sets trailing() function:
2778 * node-set set:trailing (node-set, node-set)
2779 * @nodes1 and @nodes2 are sorted by document order, then
2780 * #xmlXPathTrailingSorted is called.
2781 *
2782 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2783 * in document order, @nodes1 if @nodes2 is NULL or empty or
2784 * an empty node-set if @nodes1 doesn't contain @nodes2
2785 */
2786xmlNodeSetPtr
2787xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2788 if (xmlXPathNodeSetIsEmpty(nodes2))
2789 return(nodes1);
2790 if (xmlXPathNodeSetIsEmpty(nodes1))
2791 return(xmlXPathNodeSetCreate(NULL));
2792 xmlXPathNodeSetSort(nodes1);
2793 xmlXPathNodeSetSort(nodes2);
2794 return(xmlXPathNodeTrailingSorted(nodes1,
2795 xmlXPathNodeSetItem(nodes2, 0)));
2796}
2797
Owen Taylor3473f882001-02-23 17:55:21 +00002798/************************************************************************
2799 * *
2800 * Routines to handle extra functions *
2801 * *
2802 ************************************************************************/
2803
2804/**
2805 * xmlXPathRegisterFunc:
2806 * @ctxt: the XPath context
2807 * @name: the function name
2808 * @f: the function implementation or NULL
2809 *
2810 * Register a new function. If @f is NULL it unregisters the function
2811 *
2812 * Returns 0 in case of success, -1 in case of error
2813 */
2814int
2815xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2816 xmlXPathFunction f) {
2817 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2818}
2819
2820/**
2821 * xmlXPathRegisterFuncNS:
2822 * @ctxt: the XPath context
2823 * @name: the function name
2824 * @ns_uri: the function namespace URI
2825 * @f: the function implementation or NULL
2826 *
2827 * Register a new function. If @f is NULL it unregisters the function
2828 *
2829 * Returns 0 in case of success, -1 in case of error
2830 */
2831int
2832xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2833 const xmlChar *ns_uri, xmlXPathFunction f) {
2834 if (ctxt == NULL)
2835 return(-1);
2836 if (name == NULL)
2837 return(-1);
2838
2839 if (ctxt->funcHash == NULL)
2840 ctxt->funcHash = xmlHashCreate(0);
2841 if (ctxt->funcHash == NULL)
2842 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002843 if (f == NULL)
2844 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00002845 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00002846}
2847
2848/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002849 * xmlXPathRegisterFuncLookup:
2850 * @ctxt: the XPath context
2851 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002852 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002853 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002854 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002855 */
2856void
2857xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2858 xmlXPathFuncLookupFunc f,
2859 void *funcCtxt) {
2860 if (ctxt == NULL)
2861 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002862 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002863 ctxt->funcLookupData = funcCtxt;
2864}
2865
2866/**
Owen Taylor3473f882001-02-23 17:55:21 +00002867 * xmlXPathFunctionLookup:
2868 * @ctxt: the XPath context
2869 * @name: the function name
2870 *
2871 * Search in the Function array of the context for the given
2872 * function.
2873 *
2874 * Returns the xmlXPathFunction or NULL if not found
2875 */
2876xmlXPathFunction
2877xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002878 if (ctxt == NULL)
2879 return (NULL);
2880
2881 if (ctxt->funcLookupFunc != NULL) {
2882 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002883 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002884
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002885 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002886 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002887 if (ret != NULL)
2888 return(ret);
2889 }
Owen Taylor3473f882001-02-23 17:55:21 +00002890 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2891}
2892
2893/**
2894 * xmlXPathFunctionLookupNS:
2895 * @ctxt: the XPath context
2896 * @name: the function name
2897 * @ns_uri: the function namespace URI
2898 *
2899 * Search in the Function array of the context for the given
2900 * function.
2901 *
2902 * Returns the xmlXPathFunction or NULL if not found
2903 */
2904xmlXPathFunction
2905xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2906 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00002907 xmlXPathFunction ret;
2908
Owen Taylor3473f882001-02-23 17:55:21 +00002909 if (ctxt == NULL)
2910 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002911 if (name == NULL)
2912 return(NULL);
2913
Thomas Broyerba4ad322001-07-26 16:55:21 +00002914 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002915 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002916
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002917 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002918 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002919 if (ret != NULL)
2920 return(ret);
2921 }
2922
2923 if (ctxt->funcHash == NULL)
2924 return(NULL);
2925
William M. Brackad0e67c2004-12-01 14:35:10 +00002926 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
2927 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002928}
2929
2930/**
2931 * xmlXPathRegisteredFuncsCleanup:
2932 * @ctxt: the XPath context
2933 *
2934 * Cleanup the XPath context data associated to registered functions
2935 */
2936void
2937xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2938 if (ctxt == NULL)
2939 return;
2940
2941 xmlHashFree(ctxt->funcHash, NULL);
2942 ctxt->funcHash = NULL;
2943}
2944
2945/************************************************************************
2946 * *
William M. Brack08171912003-12-29 02:52:11 +00002947 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00002948 * *
2949 ************************************************************************/
2950
2951/**
2952 * xmlXPathRegisterVariable:
2953 * @ctxt: the XPath context
2954 * @name: the variable name
2955 * @value: the variable value or NULL
2956 *
2957 * Register a new variable value. If @value is NULL it unregisters
2958 * the variable
2959 *
2960 * Returns 0 in case of success, -1 in case of error
2961 */
2962int
2963xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2964 xmlXPathObjectPtr value) {
2965 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2966}
2967
2968/**
2969 * xmlXPathRegisterVariableNS:
2970 * @ctxt: the XPath context
2971 * @name: the variable name
2972 * @ns_uri: the variable namespace URI
2973 * @value: the variable value or NULL
2974 *
2975 * Register a new variable value. If @value is NULL it unregisters
2976 * the variable
2977 *
2978 * Returns 0 in case of success, -1 in case of error
2979 */
2980int
2981xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2982 const xmlChar *ns_uri,
2983 xmlXPathObjectPtr value) {
2984 if (ctxt == NULL)
2985 return(-1);
2986 if (name == NULL)
2987 return(-1);
2988
2989 if (ctxt->varHash == NULL)
2990 ctxt->varHash = xmlHashCreate(0);
2991 if (ctxt->varHash == NULL)
2992 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002993 if (value == NULL)
2994 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2995 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002996 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2997 (void *) value,
2998 (xmlHashDeallocator)xmlXPathFreeObject));
2999}
3000
3001/**
3002 * xmlXPathRegisterVariableLookup:
3003 * @ctxt: the XPath context
3004 * @f: the lookup function
3005 * @data: the lookup data
3006 *
3007 * register an external mechanism to do variable lookup
3008 */
3009void
3010xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
3011 xmlXPathVariableLookupFunc f, void *data) {
3012 if (ctxt == NULL)
3013 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00003014 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00003015 ctxt->varLookupData = data;
3016}
3017
3018/**
3019 * xmlXPathVariableLookup:
3020 * @ctxt: the XPath context
3021 * @name: the variable name
3022 *
3023 * Search in the Variable array of the context for the given
3024 * variable value.
3025 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003026 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003027 */
3028xmlXPathObjectPtr
3029xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3030 if (ctxt == NULL)
3031 return(NULL);
3032
3033 if (ctxt->varLookupFunc != NULL) {
3034 xmlXPathObjectPtr ret;
3035
3036 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3037 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00003038 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003039 }
3040 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3041}
3042
3043/**
3044 * xmlXPathVariableLookupNS:
3045 * @ctxt: the XPath context
3046 * @name: the variable name
3047 * @ns_uri: the variable namespace URI
3048 *
3049 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00003050 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00003051 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003052 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003053 */
3054xmlXPathObjectPtr
3055xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3056 const xmlChar *ns_uri) {
3057 if (ctxt == NULL)
3058 return(NULL);
3059
3060 if (ctxt->varLookupFunc != NULL) {
3061 xmlXPathObjectPtr ret;
3062
3063 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3064 (ctxt->varLookupData, name, ns_uri);
3065 if (ret != NULL) return(ret);
3066 }
3067
3068 if (ctxt->varHash == NULL)
3069 return(NULL);
3070 if (name == NULL)
3071 return(NULL);
3072
Daniel Veillard8c357d52001-07-03 23:43:33 +00003073 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3074 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00003075}
3076
3077/**
3078 * xmlXPathRegisteredVariablesCleanup:
3079 * @ctxt: the XPath context
3080 *
3081 * Cleanup the XPath context data associated to registered variables
3082 */
3083void
3084xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3085 if (ctxt == NULL)
3086 return;
3087
Daniel Veillard76d66f42001-05-16 21:05:17 +00003088 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00003089 ctxt->varHash = NULL;
3090}
3091
3092/**
3093 * xmlXPathRegisterNs:
3094 * @ctxt: the XPath context
3095 * @prefix: the namespace prefix
3096 * @ns_uri: the namespace name
3097 *
3098 * Register a new namespace. If @ns_uri is NULL it unregisters
3099 * the namespace
3100 *
3101 * Returns 0 in case of success, -1 in case of error
3102 */
3103int
3104xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3105 const xmlChar *ns_uri) {
3106 if (ctxt == NULL)
3107 return(-1);
3108 if (prefix == NULL)
3109 return(-1);
3110
3111 if (ctxt->nsHash == NULL)
3112 ctxt->nsHash = xmlHashCreate(10);
3113 if (ctxt->nsHash == NULL)
3114 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003115 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003116 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003117 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003118 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003119 (xmlHashDeallocator)xmlFree));
3120}
3121
3122/**
3123 * xmlXPathNsLookup:
3124 * @ctxt: the XPath context
3125 * @prefix: the namespace prefix value
3126 *
3127 * Search in the namespace declaration array of the context for the given
3128 * namespace name associated to the given prefix
3129 *
3130 * Returns the value or NULL if not found
3131 */
3132const xmlChar *
3133xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3134 if (ctxt == NULL)
3135 return(NULL);
3136 if (prefix == NULL)
3137 return(NULL);
3138
3139#ifdef XML_XML_NAMESPACE
3140 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3141 return(XML_XML_NAMESPACE);
3142#endif
3143
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003144 if (ctxt->namespaces != NULL) {
3145 int i;
3146
3147 for (i = 0;i < ctxt->nsNr;i++) {
3148 if ((ctxt->namespaces[i] != NULL) &&
3149 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3150 return(ctxt->namespaces[i]->href);
3151 }
3152 }
Owen Taylor3473f882001-02-23 17:55:21 +00003153
3154 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3155}
3156
3157/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003158 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003159 * @ctxt: the XPath context
3160 *
3161 * Cleanup the XPath context data associated to registered variables
3162 */
3163void
3164xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3165 if (ctxt == NULL)
3166 return;
3167
Daniel Veillard42766c02002-08-22 20:52:17 +00003168 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003169 ctxt->nsHash = NULL;
3170}
3171
3172/************************************************************************
3173 * *
3174 * Routines to handle Values *
3175 * *
3176 ************************************************************************/
3177
William M. Brack08171912003-12-29 02:52:11 +00003178/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003179
3180/**
3181 * xmlXPathNewFloat:
3182 * @val: the double value
3183 *
3184 * Create a new xmlXPathObjectPtr of type double and of value @val
3185 *
3186 * Returns the newly created object.
3187 */
3188xmlXPathObjectPtr
3189xmlXPathNewFloat(double val) {
3190 xmlXPathObjectPtr ret;
3191
3192 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3193 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003194 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003195 return(NULL);
3196 }
3197 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3198 ret->type = XPATH_NUMBER;
3199 ret->floatval = val;
3200 return(ret);
3201}
3202
3203/**
3204 * xmlXPathNewBoolean:
3205 * @val: the boolean value
3206 *
3207 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3208 *
3209 * Returns the newly created object.
3210 */
3211xmlXPathObjectPtr
3212xmlXPathNewBoolean(int val) {
3213 xmlXPathObjectPtr ret;
3214
3215 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3216 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003217 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003218 return(NULL);
3219 }
3220 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3221 ret->type = XPATH_BOOLEAN;
3222 ret->boolval = (val != 0);
3223 return(ret);
3224}
3225
3226/**
3227 * xmlXPathNewString:
3228 * @val: the xmlChar * value
3229 *
3230 * Create a new xmlXPathObjectPtr of type string and of value @val
3231 *
3232 * Returns the newly created object.
3233 */
3234xmlXPathObjectPtr
3235xmlXPathNewString(const xmlChar *val) {
3236 xmlXPathObjectPtr ret;
3237
3238 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3239 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003240 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003241 return(NULL);
3242 }
3243 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3244 ret->type = XPATH_STRING;
3245 if (val != NULL)
3246 ret->stringval = xmlStrdup(val);
3247 else
3248 ret->stringval = xmlStrdup((const xmlChar *)"");
3249 return(ret);
3250}
3251
3252/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003253 * xmlXPathWrapString:
3254 * @val: the xmlChar * value
3255 *
3256 * Wraps the @val string into an XPath object.
3257 *
3258 * Returns the newly created object.
3259 */
3260xmlXPathObjectPtr
3261xmlXPathWrapString (xmlChar *val) {
3262 xmlXPathObjectPtr ret;
3263
3264 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3265 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003266 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003267 return(NULL);
3268 }
3269 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3270 ret->type = XPATH_STRING;
3271 ret->stringval = val;
3272 return(ret);
3273}
3274
3275/**
Owen Taylor3473f882001-02-23 17:55:21 +00003276 * xmlXPathNewCString:
3277 * @val: the char * value
3278 *
3279 * Create a new xmlXPathObjectPtr of type string and of value @val
3280 *
3281 * Returns the newly created object.
3282 */
3283xmlXPathObjectPtr
3284xmlXPathNewCString(const char *val) {
3285 xmlXPathObjectPtr ret;
3286
3287 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3288 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003289 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003290 return(NULL);
3291 }
3292 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3293 ret->type = XPATH_STRING;
3294 ret->stringval = xmlStrdup(BAD_CAST val);
3295 return(ret);
3296}
3297
3298/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003299 * xmlXPathWrapCString:
3300 * @val: the char * value
3301 *
3302 * Wraps a string into an XPath object.
3303 *
3304 * Returns the newly created object.
3305 */
3306xmlXPathObjectPtr
3307xmlXPathWrapCString (char * val) {
3308 return(xmlXPathWrapString((xmlChar *)(val)));
3309}
3310
3311/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003312 * xmlXPathWrapExternal:
3313 * @val: the user data
3314 *
3315 * Wraps the @val data into an XPath object.
3316 *
3317 * Returns the newly created object.
3318 */
3319xmlXPathObjectPtr
3320xmlXPathWrapExternal (void *val) {
3321 xmlXPathObjectPtr ret;
3322
3323 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3324 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003325 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003326 return(NULL);
3327 }
3328 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3329 ret->type = XPATH_USERS;
3330 ret->user = val;
3331 return(ret);
3332}
3333
3334/**
Owen Taylor3473f882001-02-23 17:55:21 +00003335 * xmlXPathObjectCopy:
3336 * @val: the original object
3337 *
3338 * allocate a new copy of a given object
3339 *
3340 * Returns the newly created object.
3341 */
3342xmlXPathObjectPtr
3343xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3344 xmlXPathObjectPtr ret;
3345
3346 if (val == NULL)
3347 return(NULL);
3348
3349 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3350 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003351 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003352 return(NULL);
3353 }
3354 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3355 switch (val->type) {
3356 case XPATH_BOOLEAN:
3357 case XPATH_NUMBER:
3358 case XPATH_POINT:
3359 case XPATH_RANGE:
3360 break;
3361 case XPATH_STRING:
3362 ret->stringval = xmlStrdup(val->stringval);
3363 break;
3364 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00003365#if 0
3366/*
3367 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
3368 this previous handling is no longer correct, and can cause some serious
3369 problems (ref. bug 145547)
3370*/
Owen Taylor3473f882001-02-23 17:55:21 +00003371 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003372 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003373 xmlNodePtr cur, tmp;
3374 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003375
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003376 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003377 top = xmlNewDoc(NULL);
3378 top->name = (char *)
3379 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003380 ret->user = top;
3381 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003382 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003383 cur = val->nodesetval->nodeTab[0]->children;
3384 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003385 tmp = xmlDocCopyNode(cur, top, 1);
3386 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003387 cur = cur->next;
3388 }
3389 }
William M. Bracke9449c52004-07-11 14:41:20 +00003390
Daniel Veillard9adc0462003-03-24 18:39:54 +00003391 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003392 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003393 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003394 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003395 break;
William M. Bracke9449c52004-07-11 14:41:20 +00003396#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003397 case XPATH_NODESET:
3398 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003399 /* Do not deallocate the copied tree value */
3400 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003401 break;
3402 case XPATH_LOCATIONSET:
3403#ifdef LIBXML_XPTR_ENABLED
3404 {
3405 xmlLocationSetPtr loc = val->user;
3406 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3407 break;
3408 }
3409#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003410 case XPATH_USERS:
3411 ret->user = val->user;
3412 break;
3413 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003414 xmlGenericError(xmlGenericErrorContext,
3415 "xmlXPathObjectCopy: unsupported type %d\n",
3416 val->type);
3417 break;
3418 }
3419 return(ret);
3420}
3421
3422/**
3423 * xmlXPathFreeObject:
3424 * @obj: the object to free
3425 *
3426 * Free up an xmlXPathObjectPtr object.
3427 */
3428void
3429xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3430 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003431 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003432 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00003433#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003434 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003435 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003436 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003437 } else
3438#endif
3439 if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003440 xmlXPathFreeValueTree(obj->nodesetval);
3441 } else {
3442 if (obj->nodesetval != NULL)
3443 xmlXPathFreeNodeSet(obj->nodesetval);
3444 }
Owen Taylor3473f882001-02-23 17:55:21 +00003445#ifdef LIBXML_XPTR_ENABLED
3446 } else if (obj->type == XPATH_LOCATIONSET) {
3447 if (obj->user != NULL)
3448 xmlXPtrFreeLocationSet(obj->user);
3449#endif
3450 } else if (obj->type == XPATH_STRING) {
3451 if (obj->stringval != NULL)
3452 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003453 }
3454
Owen Taylor3473f882001-02-23 17:55:21 +00003455 xmlFree(obj);
3456}
3457
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003458
3459/************************************************************************
3460 * *
3461 * Type Casting Routines *
3462 * *
3463 ************************************************************************/
3464
3465/**
3466 * xmlXPathCastBooleanToString:
3467 * @val: a boolean
3468 *
3469 * Converts a boolean to its string value.
3470 *
3471 * Returns a newly allocated string.
3472 */
3473xmlChar *
3474xmlXPathCastBooleanToString (int val) {
3475 xmlChar *ret;
3476 if (val)
3477 ret = xmlStrdup((const xmlChar *) "true");
3478 else
3479 ret = xmlStrdup((const xmlChar *) "false");
3480 return(ret);
3481}
3482
3483/**
3484 * xmlXPathCastNumberToString:
3485 * @val: a number
3486 *
3487 * Converts a number to its string value.
3488 *
3489 * Returns a newly allocated string.
3490 */
3491xmlChar *
3492xmlXPathCastNumberToString (double val) {
3493 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003494 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003495 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003496 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003497 break;
3498 case -1:
3499 ret = xmlStrdup((const xmlChar *) "-Infinity");
3500 break;
3501 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003502 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003503 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003504 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3505 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003506 } else {
3507 /* could be improved */
3508 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00003509 xmlXPathFormatNumber(val, buf, 99);
3510 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003511 ret = xmlStrdup((const xmlChar *) buf);
3512 }
3513 }
3514 return(ret);
3515}
3516
3517/**
3518 * xmlXPathCastNodeToString:
3519 * @node: a node
3520 *
3521 * Converts a node to its string value.
3522 *
3523 * Returns a newly allocated string.
3524 */
3525xmlChar *
3526xmlXPathCastNodeToString (xmlNodePtr node) {
3527 return(xmlNodeGetContent(node));
3528}
3529
3530/**
3531 * xmlXPathCastNodeSetToString:
3532 * @ns: a node-set
3533 *
3534 * Converts a node-set to its string value.
3535 *
3536 * Returns a newly allocated string.
3537 */
3538xmlChar *
3539xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3540 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3541 return(xmlStrdup((const xmlChar *) ""));
3542
3543 xmlXPathNodeSetSort(ns);
3544 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3545}
3546
3547/**
3548 * xmlXPathCastToString:
3549 * @val: an XPath object
3550 *
3551 * Converts an existing object to its string() equivalent
3552 *
3553 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003554 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003555 * string object).
3556 */
3557xmlChar *
3558xmlXPathCastToString(xmlXPathObjectPtr val) {
3559 xmlChar *ret = NULL;
3560
3561 if (val == NULL)
3562 return(xmlStrdup((const xmlChar *) ""));
3563 switch (val->type) {
3564 case XPATH_UNDEFINED:
3565#ifdef DEBUG_EXPR
3566 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3567#endif
3568 ret = xmlStrdup((const xmlChar *) "");
3569 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003570 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003571 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003572 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3573 break;
3574 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003575 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003576 case XPATH_BOOLEAN:
3577 ret = xmlXPathCastBooleanToString(val->boolval);
3578 break;
3579 case XPATH_NUMBER: {
3580 ret = xmlXPathCastNumberToString(val->floatval);
3581 break;
3582 }
3583 case XPATH_USERS:
3584 case XPATH_POINT:
3585 case XPATH_RANGE:
3586 case XPATH_LOCATIONSET:
3587 TODO
3588 ret = xmlStrdup((const xmlChar *) "");
3589 break;
3590 }
3591 return(ret);
3592}
3593
3594/**
3595 * xmlXPathConvertString:
3596 * @val: an XPath object
3597 *
3598 * Converts an existing object to its string() equivalent
3599 *
3600 * Returns the new object, the old one is freed (or the operation
3601 * is done directly on @val)
3602 */
3603xmlXPathObjectPtr
3604xmlXPathConvertString(xmlXPathObjectPtr val) {
3605 xmlChar *res = NULL;
3606
3607 if (val == NULL)
3608 return(xmlXPathNewCString(""));
3609
3610 switch (val->type) {
3611 case XPATH_UNDEFINED:
3612#ifdef DEBUG_EXPR
3613 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3614#endif
3615 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003616 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003617 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003618 res = xmlXPathCastNodeSetToString(val->nodesetval);
3619 break;
3620 case XPATH_STRING:
3621 return(val);
3622 case XPATH_BOOLEAN:
3623 res = xmlXPathCastBooleanToString(val->boolval);
3624 break;
3625 case XPATH_NUMBER:
3626 res = xmlXPathCastNumberToString(val->floatval);
3627 break;
3628 case XPATH_USERS:
3629 case XPATH_POINT:
3630 case XPATH_RANGE:
3631 case XPATH_LOCATIONSET:
3632 TODO;
3633 break;
3634 }
3635 xmlXPathFreeObject(val);
3636 if (res == NULL)
3637 return(xmlXPathNewCString(""));
3638 return(xmlXPathWrapString(res));
3639}
3640
3641/**
3642 * xmlXPathCastBooleanToNumber:
3643 * @val: a boolean
3644 *
3645 * Converts a boolean to its number value
3646 *
3647 * Returns the number value
3648 */
3649double
3650xmlXPathCastBooleanToNumber(int val) {
3651 if (val)
3652 return(1.0);
3653 return(0.0);
3654}
3655
3656/**
3657 * xmlXPathCastStringToNumber:
3658 * @val: a string
3659 *
3660 * Converts a string to its number value
3661 *
3662 * Returns the number value
3663 */
3664double
3665xmlXPathCastStringToNumber(const xmlChar * val) {
3666 return(xmlXPathStringEvalNumber(val));
3667}
3668
3669/**
3670 * xmlXPathCastNodeToNumber:
3671 * @node: a node
3672 *
3673 * Converts a node to its number value
3674 *
3675 * Returns the number value
3676 */
3677double
3678xmlXPathCastNodeToNumber (xmlNodePtr node) {
3679 xmlChar *strval;
3680 double ret;
3681
3682 if (node == NULL)
3683 return(xmlXPathNAN);
3684 strval = xmlXPathCastNodeToString(node);
3685 if (strval == NULL)
3686 return(xmlXPathNAN);
3687 ret = xmlXPathCastStringToNumber(strval);
3688 xmlFree(strval);
3689
3690 return(ret);
3691}
3692
3693/**
3694 * xmlXPathCastNodeSetToNumber:
3695 * @ns: a node-set
3696 *
3697 * Converts a node-set to its number value
3698 *
3699 * Returns the number value
3700 */
3701double
3702xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3703 xmlChar *str;
3704 double ret;
3705
3706 if (ns == NULL)
3707 return(xmlXPathNAN);
3708 str = xmlXPathCastNodeSetToString(ns);
3709 ret = xmlXPathCastStringToNumber(str);
3710 xmlFree(str);
3711 return(ret);
3712}
3713
3714/**
3715 * xmlXPathCastToNumber:
3716 * @val: an XPath object
3717 *
3718 * Converts an XPath object to its number value
3719 *
3720 * Returns the number value
3721 */
3722double
3723xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3724 double ret = 0.0;
3725
3726 if (val == NULL)
3727 return(xmlXPathNAN);
3728 switch (val->type) {
3729 case XPATH_UNDEFINED:
3730#ifdef DEGUB_EXPR
3731 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3732#endif
3733 ret = xmlXPathNAN;
3734 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003735 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003736 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003737 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3738 break;
3739 case XPATH_STRING:
3740 ret = xmlXPathCastStringToNumber(val->stringval);
3741 break;
3742 case XPATH_NUMBER:
3743 ret = val->floatval;
3744 break;
3745 case XPATH_BOOLEAN:
3746 ret = xmlXPathCastBooleanToNumber(val->boolval);
3747 break;
3748 case XPATH_USERS:
3749 case XPATH_POINT:
3750 case XPATH_RANGE:
3751 case XPATH_LOCATIONSET:
3752 TODO;
3753 ret = xmlXPathNAN;
3754 break;
3755 }
3756 return(ret);
3757}
3758
3759/**
3760 * xmlXPathConvertNumber:
3761 * @val: an XPath object
3762 *
3763 * Converts an existing object to its number() equivalent
3764 *
3765 * Returns the new object, the old one is freed (or the operation
3766 * is done directly on @val)
3767 */
3768xmlXPathObjectPtr
3769xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3770 xmlXPathObjectPtr ret;
3771
3772 if (val == NULL)
3773 return(xmlXPathNewFloat(0.0));
3774 if (val->type == XPATH_NUMBER)
3775 return(val);
3776 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3777 xmlXPathFreeObject(val);
3778 return(ret);
3779}
3780
3781/**
3782 * xmlXPathCastNumberToBoolean:
3783 * @val: a number
3784 *
3785 * Converts a number to its boolean value
3786 *
3787 * Returns the boolean value
3788 */
3789int
3790xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003791 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003792 return(0);
3793 return(1);
3794}
3795
3796/**
3797 * xmlXPathCastStringToBoolean:
3798 * @val: a string
3799 *
3800 * Converts a string to its boolean value
3801 *
3802 * Returns the boolean value
3803 */
3804int
3805xmlXPathCastStringToBoolean (const xmlChar *val) {
3806 if ((val == NULL) || (xmlStrlen(val) == 0))
3807 return(0);
3808 return(1);
3809}
3810
3811/**
3812 * xmlXPathCastNodeSetToBoolean:
3813 * @ns: a node-set
3814 *
3815 * Converts a node-set to its boolean value
3816 *
3817 * Returns the boolean value
3818 */
3819int
3820xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3821 if ((ns == NULL) || (ns->nodeNr == 0))
3822 return(0);
3823 return(1);
3824}
3825
3826/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003827 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003828 * @val: an XPath object
3829 *
3830 * Converts an XPath object to its boolean value
3831 *
3832 * Returns the boolean value
3833 */
3834int
3835xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3836 int ret = 0;
3837
3838 if (val == NULL)
3839 return(0);
3840 switch (val->type) {
3841 case XPATH_UNDEFINED:
3842#ifdef DEBUG_EXPR
3843 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3844#endif
3845 ret = 0;
3846 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003847 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003848 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003849 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3850 break;
3851 case XPATH_STRING:
3852 ret = xmlXPathCastStringToBoolean(val->stringval);
3853 break;
3854 case XPATH_NUMBER:
3855 ret = xmlXPathCastNumberToBoolean(val->floatval);
3856 break;
3857 case XPATH_BOOLEAN:
3858 ret = val->boolval;
3859 break;
3860 case XPATH_USERS:
3861 case XPATH_POINT:
3862 case XPATH_RANGE:
3863 case XPATH_LOCATIONSET:
3864 TODO;
3865 ret = 0;
3866 break;
3867 }
3868 return(ret);
3869}
3870
3871
3872/**
3873 * xmlXPathConvertBoolean:
3874 * @val: an XPath object
3875 *
3876 * Converts an existing object to its boolean() equivalent
3877 *
3878 * Returns the new object, the old one is freed (or the operation
3879 * is done directly on @val)
3880 */
3881xmlXPathObjectPtr
3882xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3883 xmlXPathObjectPtr ret;
3884
3885 if (val == NULL)
3886 return(xmlXPathNewBoolean(0));
3887 if (val->type == XPATH_BOOLEAN)
3888 return(val);
3889 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3890 xmlXPathFreeObject(val);
3891 return(ret);
3892}
3893
Owen Taylor3473f882001-02-23 17:55:21 +00003894/************************************************************************
3895 * *
3896 * Routines to handle XPath contexts *
3897 * *
3898 ************************************************************************/
3899
3900/**
3901 * xmlXPathNewContext:
3902 * @doc: the XML document
3903 *
3904 * Create a new xmlXPathContext
3905 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003906 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003907 */
3908xmlXPathContextPtr
3909xmlXPathNewContext(xmlDocPtr doc) {
3910 xmlXPathContextPtr ret;
3911
3912 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3913 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003914 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003915 return(NULL);
3916 }
3917 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3918 ret->doc = doc;
3919 ret->node = NULL;
3920
3921 ret->varHash = NULL;
3922
3923 ret->nb_types = 0;
3924 ret->max_types = 0;
3925 ret->types = NULL;
3926
3927 ret->funcHash = xmlHashCreate(0);
3928
3929 ret->nb_axis = 0;
3930 ret->max_axis = 0;
3931 ret->axis = NULL;
3932
3933 ret->nsHash = NULL;
3934 ret->user = NULL;
3935
3936 ret->contextSize = -1;
3937 ret->proximityPosition = -1;
3938
3939 xmlXPathRegisterAllFunctions(ret);
3940
3941 return(ret);
3942}
3943
3944/**
3945 * xmlXPathFreeContext:
3946 * @ctxt: the context to free
3947 *
3948 * Free up an xmlXPathContext
3949 */
3950void
3951xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00003952 if (ctxt == NULL) return;
3953
Owen Taylor3473f882001-02-23 17:55:21 +00003954 xmlXPathRegisteredNsCleanup(ctxt);
3955 xmlXPathRegisteredFuncsCleanup(ctxt);
3956 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00003957 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00003958 xmlFree(ctxt);
3959}
3960
3961/************************************************************************
3962 * *
3963 * Routines to handle XPath parser contexts *
3964 * *
3965 ************************************************************************/
3966
3967#define CHECK_CTXT(ctxt) \
3968 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00003969 __xmlRaiseError(NULL, NULL, NULL, \
3970 NULL, NULL, XML_FROM_XPATH, \
3971 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
3972 __FILE__, __LINE__, \
3973 NULL, NULL, NULL, 0, 0, \
3974 "NULL context pointer\n"); \
3975 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00003976 } \
3977
3978
3979#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00003980 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
3981 (ctxt->doc->children == NULL)) { \
3982 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00003983 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00003984 }
Owen Taylor3473f882001-02-23 17:55:21 +00003985
3986
3987/**
3988 * xmlXPathNewParserContext:
3989 * @str: the XPath expression
3990 * @ctxt: the XPath context
3991 *
3992 * Create a new xmlXPathParserContext
3993 *
3994 * Returns the xmlXPathParserContext just allocated.
3995 */
3996xmlXPathParserContextPtr
3997xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3998 xmlXPathParserContextPtr ret;
3999
4000 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4001 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004002 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004003 return(NULL);
4004 }
4005 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4006 ret->cur = ret->base = str;
4007 ret->context = ctxt;
4008
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004009 ret->comp = xmlXPathNewCompExpr();
4010 if (ret->comp == NULL) {
4011 xmlFree(ret->valueTab);
4012 xmlFree(ret);
4013 return(NULL);
4014 }
Daniel Veillard4773df22004-01-23 13:15:13 +00004015 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4016 ret->comp->dict = ctxt->dict;
4017 xmlDictReference(ret->comp->dict);
4018 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004019
4020 return(ret);
4021}
4022
4023/**
4024 * xmlXPathCompParserContext:
4025 * @comp: the XPath compiled expression
4026 * @ctxt: the XPath context
4027 *
4028 * Create a new xmlXPathParserContext when processing a compiled expression
4029 *
4030 * Returns the xmlXPathParserContext just allocated.
4031 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004032static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004033xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4034 xmlXPathParserContextPtr ret;
4035
4036 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4037 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004038 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004039 return(NULL);
4040 }
4041 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4042
Owen Taylor3473f882001-02-23 17:55:21 +00004043 /* Allocate the value stack */
4044 ret->valueTab = (xmlXPathObjectPtr *)
4045 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004046 if (ret->valueTab == NULL) {
4047 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004048 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004049 return(NULL);
4050 }
Owen Taylor3473f882001-02-23 17:55:21 +00004051 ret->valueNr = 0;
4052 ret->valueMax = 10;
4053 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004054
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004055 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004056 ret->comp = comp;
4057
Owen Taylor3473f882001-02-23 17:55:21 +00004058 return(ret);
4059}
4060
4061/**
4062 * xmlXPathFreeParserContext:
4063 * @ctxt: the context to free
4064 *
4065 * Free up an xmlXPathParserContext
4066 */
4067void
4068xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
4069 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004070 xmlFree(ctxt->valueTab);
4071 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00004072 if (ctxt->comp != NULL) {
4073#ifdef XPATH_STREAMING
4074 if (ctxt->comp->stream != NULL) {
4075 xmlFreePatternList(ctxt->comp->stream);
4076 ctxt->comp->stream = NULL;
4077 }
4078#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004079 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00004080 }
Owen Taylor3473f882001-02-23 17:55:21 +00004081 xmlFree(ctxt);
4082}
4083
4084/************************************************************************
4085 * *
4086 * The implicit core function library *
4087 * *
4088 ************************************************************************/
4089
Owen Taylor3473f882001-02-23 17:55:21 +00004090/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004091 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00004092 * @node: a node pointer
4093 *
4094 * Function computing the beginning of the string value of the node,
4095 * used to speed up comparisons
4096 *
4097 * Returns an int usable as a hash
4098 */
4099static unsigned int
4100xmlXPathNodeValHash(xmlNodePtr node) {
4101 int len = 2;
4102 const xmlChar * string = NULL;
4103 xmlNodePtr tmp = NULL;
4104 unsigned int ret = 0;
4105
4106 if (node == NULL)
4107 return(0);
4108
Daniel Veillard9adc0462003-03-24 18:39:54 +00004109 if (node->type == XML_DOCUMENT_NODE) {
4110 tmp = xmlDocGetRootElement((xmlDocPtr) node);
4111 if (tmp == NULL)
4112 node = node->children;
4113 else
4114 node = tmp;
4115
4116 if (node == NULL)
4117 return(0);
4118 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004119
4120 switch (node->type) {
4121 case XML_COMMENT_NODE:
4122 case XML_PI_NODE:
4123 case XML_CDATA_SECTION_NODE:
4124 case XML_TEXT_NODE:
4125 string = node->content;
4126 if (string == NULL)
4127 return(0);
4128 if (string[0] == 0)
4129 return(0);
4130 return(((unsigned int) string[0]) +
4131 (((unsigned int) string[1]) << 8));
4132 case XML_NAMESPACE_DECL:
4133 string = ((xmlNsPtr)node)->href;
4134 if (string == NULL)
4135 return(0);
4136 if (string[0] == 0)
4137 return(0);
4138 return(((unsigned int) string[0]) +
4139 (((unsigned int) string[1]) << 8));
4140 case XML_ATTRIBUTE_NODE:
4141 tmp = ((xmlAttrPtr) node)->children;
4142 break;
4143 case XML_ELEMENT_NODE:
4144 tmp = node->children;
4145 break;
4146 default:
4147 return(0);
4148 }
4149 while (tmp != NULL) {
4150 switch (tmp->type) {
4151 case XML_COMMENT_NODE:
4152 case XML_PI_NODE:
4153 case XML_CDATA_SECTION_NODE:
4154 case XML_TEXT_NODE:
4155 string = tmp->content;
4156 break;
4157 case XML_NAMESPACE_DECL:
4158 string = ((xmlNsPtr)tmp)->href;
4159 break;
4160 default:
4161 break;
4162 }
4163 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004164 if (len == 1) {
4165 return(ret + (((unsigned int) string[0]) << 8));
4166 }
4167 if (string[1] == 0) {
4168 len = 1;
4169 ret = (unsigned int) string[0];
4170 } else {
4171 return(((unsigned int) string[0]) +
4172 (((unsigned int) string[1]) << 8));
4173 }
4174 }
4175 /*
4176 * Skip to next node
4177 */
4178 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4179 if (tmp->children->type != XML_ENTITY_DECL) {
4180 tmp = tmp->children;
4181 continue;
4182 }
4183 }
4184 if (tmp == node)
4185 break;
4186
4187 if (tmp->next != NULL) {
4188 tmp = tmp->next;
4189 continue;
4190 }
4191
4192 do {
4193 tmp = tmp->parent;
4194 if (tmp == NULL)
4195 break;
4196 if (tmp == node) {
4197 tmp = NULL;
4198 break;
4199 }
4200 if (tmp->next != NULL) {
4201 tmp = tmp->next;
4202 break;
4203 }
4204 } while (tmp != NULL);
4205 }
4206 return(ret);
4207}
4208
4209/**
4210 * xmlXPathStringHash:
4211 * @string: a string
4212 *
4213 * Function computing the beginning of the string value of the node,
4214 * used to speed up comparisons
4215 *
4216 * Returns an int usable as a hash
4217 */
4218static unsigned int
4219xmlXPathStringHash(const xmlChar * string) {
4220 if (string == NULL)
4221 return((unsigned int) 0);
4222 if (string[0] == 0)
4223 return(0);
4224 return(((unsigned int) string[0]) +
4225 (((unsigned int) string[1]) << 8));
4226}
4227
4228/**
Owen Taylor3473f882001-02-23 17:55:21 +00004229 * xmlXPathCompareNodeSetFloat:
4230 * @ctxt: the XPath Parser context
4231 * @inf: less than (1) or greater than (0)
4232 * @strict: is the comparison strict
4233 * @arg: the node set
4234 * @f: the value
4235 *
4236 * Implement the compare operation between a nodeset and a number
4237 * @ns < @val (1, 1, ...
4238 * @ns <= @val (1, 0, ...
4239 * @ns > @val (0, 1, ...
4240 * @ns >= @val (0, 0, ...
4241 *
4242 * If one object to be compared is a node-set and the other is a number,
4243 * then the comparison will be true if and only if there is a node in the
4244 * node-set such that the result of performing the comparison on the number
4245 * to be compared and on the result of converting the string-value of that
4246 * node to a number using the number function is true.
4247 *
4248 * Returns 0 or 1 depending on the results of the test.
4249 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004250static int
Owen Taylor3473f882001-02-23 17:55:21 +00004251xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4252 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4253 int i, ret = 0;
4254 xmlNodeSetPtr ns;
4255 xmlChar *str2;
4256
4257 if ((f == NULL) || (arg == NULL) ||
4258 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4259 xmlXPathFreeObject(arg);
4260 xmlXPathFreeObject(f);
4261 return(0);
4262 }
4263 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004264 if (ns != NULL) {
4265 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004266 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004267 if (str2 != NULL) {
4268 valuePush(ctxt,
4269 xmlXPathNewString(str2));
4270 xmlFree(str2);
4271 xmlXPathNumberFunction(ctxt, 1);
4272 valuePush(ctxt, xmlXPathObjectCopy(f));
4273 ret = xmlXPathCompareValues(ctxt, inf, strict);
4274 if (ret)
4275 break;
4276 }
4277 }
Owen Taylor3473f882001-02-23 17:55:21 +00004278 }
4279 xmlXPathFreeObject(arg);
4280 xmlXPathFreeObject(f);
4281 return(ret);
4282}
4283
4284/**
4285 * xmlXPathCompareNodeSetString:
4286 * @ctxt: the XPath Parser context
4287 * @inf: less than (1) or greater than (0)
4288 * @strict: is the comparison strict
4289 * @arg: the node set
4290 * @s: the value
4291 *
4292 * Implement the compare operation between a nodeset and a string
4293 * @ns < @val (1, 1, ...
4294 * @ns <= @val (1, 0, ...
4295 * @ns > @val (0, 1, ...
4296 * @ns >= @val (0, 0, ...
4297 *
4298 * If one object to be compared is a node-set and the other is a string,
4299 * then the comparison will be true if and only if there is a node in
4300 * the node-set such that the result of performing the comparison on the
4301 * string-value of the node and the other string is true.
4302 *
4303 * Returns 0 or 1 depending on the results of the test.
4304 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004305static int
Owen Taylor3473f882001-02-23 17:55:21 +00004306xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4307 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4308 int i, ret = 0;
4309 xmlNodeSetPtr ns;
4310 xmlChar *str2;
4311
4312 if ((s == NULL) || (arg == NULL) ||
4313 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4314 xmlXPathFreeObject(arg);
4315 xmlXPathFreeObject(s);
4316 return(0);
4317 }
4318 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004319 if (ns != NULL) {
4320 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004321 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004322 if (str2 != NULL) {
4323 valuePush(ctxt,
4324 xmlXPathNewString(str2));
4325 xmlFree(str2);
4326 valuePush(ctxt, xmlXPathObjectCopy(s));
4327 ret = xmlXPathCompareValues(ctxt, inf, strict);
4328 if (ret)
4329 break;
4330 }
4331 }
Owen Taylor3473f882001-02-23 17:55:21 +00004332 }
4333 xmlXPathFreeObject(arg);
4334 xmlXPathFreeObject(s);
4335 return(ret);
4336}
4337
4338/**
4339 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004340 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004341 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004342 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004343 * @arg2: the second node set object
4344 *
4345 * Implement the compare operation on nodesets:
4346 *
4347 * If both objects to be compared are node-sets, then the comparison
4348 * will be true if and only if there is a node in the first node-set
4349 * and a node in the second node-set such that the result of performing
4350 * the comparison on the string-values of the two nodes is true.
4351 * ....
4352 * When neither object to be compared is a node-set and the operator
4353 * is <=, <, >= or >, then the objects are compared by converting both
4354 * objects to numbers and comparing the numbers according to IEEE 754.
4355 * ....
4356 * The number function converts its argument to a number as follows:
4357 * - a string that consists of optional whitespace followed by an
4358 * optional minus sign followed by a Number followed by whitespace
4359 * is converted to the IEEE 754 number that is nearest (according
4360 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4361 * represented by the string; any other string is converted to NaN
4362 *
4363 * Conclusion all nodes need to be converted first to their string value
4364 * and then the comparison must be done when possible
4365 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004366static int
4367xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004368 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4369 int i, j, init = 0;
4370 double val1;
4371 double *values2;
4372 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004373 xmlNodeSetPtr ns1;
4374 xmlNodeSetPtr ns2;
4375
4376 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004377 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4378 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004379 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004380 }
Owen Taylor3473f882001-02-23 17:55:21 +00004381 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004382 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4383 xmlXPathFreeObject(arg1);
4384 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004385 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004386 }
Owen Taylor3473f882001-02-23 17:55:21 +00004387
4388 ns1 = arg1->nodesetval;
4389 ns2 = arg2->nodesetval;
4390
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004391 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004392 xmlXPathFreeObject(arg1);
4393 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004394 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004395 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004396 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004397 xmlXPathFreeObject(arg1);
4398 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004399 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004400 }
Owen Taylor3473f882001-02-23 17:55:21 +00004401
4402 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4403 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004404 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004405 xmlXPathFreeObject(arg1);
4406 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004407 return(0);
4408 }
4409 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004410 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004411 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004412 continue;
4413 for (j = 0;j < ns2->nodeNr;j++) {
4414 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004415 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004416 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004417 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004418 continue;
4419 if (inf && strict)
4420 ret = (val1 < values2[j]);
4421 else if (inf && !strict)
4422 ret = (val1 <= values2[j]);
4423 else if (!inf && strict)
4424 ret = (val1 > values2[j]);
4425 else if (!inf && !strict)
4426 ret = (val1 >= values2[j]);
4427 if (ret)
4428 break;
4429 }
4430 if (ret)
4431 break;
4432 init = 1;
4433 }
4434 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004435 xmlXPathFreeObject(arg1);
4436 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004437 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004438}
4439
4440/**
4441 * xmlXPathCompareNodeSetValue:
4442 * @ctxt: the XPath Parser context
4443 * @inf: less than (1) or greater than (0)
4444 * @strict: is the comparison strict
4445 * @arg: the node set
4446 * @val: the value
4447 *
4448 * Implement the compare operation between a nodeset and a value
4449 * @ns < @val (1, 1, ...
4450 * @ns <= @val (1, 0, ...
4451 * @ns > @val (0, 1, ...
4452 * @ns >= @val (0, 0, ...
4453 *
4454 * If one object to be compared is a node-set and the other is a boolean,
4455 * then the comparison will be true if and only if the result of performing
4456 * the comparison on the boolean and on the result of converting
4457 * the node-set to a boolean using the boolean function is true.
4458 *
4459 * Returns 0 or 1 depending on the results of the test.
4460 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004461static int
Owen Taylor3473f882001-02-23 17:55:21 +00004462xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4463 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4464 if ((val == NULL) || (arg == NULL) ||
4465 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4466 return(0);
4467
4468 switch(val->type) {
4469 case XPATH_NUMBER:
4470 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4471 case XPATH_NODESET:
4472 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004473 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004474 case XPATH_STRING:
4475 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4476 case XPATH_BOOLEAN:
4477 valuePush(ctxt, arg);
4478 xmlXPathBooleanFunction(ctxt, 1);
4479 valuePush(ctxt, val);
4480 return(xmlXPathCompareValues(ctxt, inf, strict));
4481 default:
4482 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004483 }
4484 return(0);
4485}
4486
4487/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004488 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004489 * @arg: the nodeset object argument
4490 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004491 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004492 *
4493 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4494 * If one object to be compared is a node-set and the other is a string,
4495 * then the comparison will be true if and only if there is a node in
4496 * the node-set such that the result of performing the comparison on the
4497 * string-value of the node and the other string is true.
4498 *
4499 * Returns 0 or 1 depending on the results of the test.
4500 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004501static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004502xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004503{
Owen Taylor3473f882001-02-23 17:55:21 +00004504 int i;
4505 xmlNodeSetPtr ns;
4506 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004507 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004508
4509 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004510 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4511 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004512 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004513 /*
4514 * A NULL nodeset compared with a string is always false
4515 * (since there is no node equal, and no node not equal)
4516 */
4517 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004518 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004519 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004520 for (i = 0; i < ns->nodeNr; i++) {
4521 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4522 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4523 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4524 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004525 if (neq)
4526 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004527 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004528 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4529 if (neq)
4530 continue;
4531 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004532 } else if (neq) {
4533 if (str2 != NULL)
4534 xmlFree(str2);
4535 return (1);
4536 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004537 if (str2 != NULL)
4538 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004539 } else if (neq)
4540 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004541 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004542 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004543}
4544
4545/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004546 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004547 * @arg: the nodeset object argument
4548 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004549 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004550 *
4551 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4552 * If one object to be compared is a node-set and the other is a number,
4553 * then the comparison will be true if and only if there is a node in
4554 * the node-set such that the result of performing the comparison on the
4555 * number to be compared and on the result of converting the string-value
4556 * of that node to a number using the number function is true.
4557 *
4558 * Returns 0 or 1 depending on the results of the test.
4559 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004560static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004561xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4562 xmlXPathObjectPtr arg, double f, int neq) {
4563 int i, ret=0;
4564 xmlNodeSetPtr ns;
4565 xmlChar *str2;
4566 xmlXPathObjectPtr val;
4567 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004568
4569 if ((arg == NULL) ||
4570 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4571 return(0);
4572
William M. Brack0c022ad2002-07-12 00:56:01 +00004573 ns = arg->nodesetval;
4574 if (ns != NULL) {
4575 for (i=0;i<ns->nodeNr;i++) {
4576 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4577 if (str2 != NULL) {
4578 valuePush(ctxt, xmlXPathNewString(str2));
4579 xmlFree(str2);
4580 xmlXPathNumberFunction(ctxt, 1);
4581 val = valuePop(ctxt);
4582 v = val->floatval;
4583 xmlXPathFreeObject(val);
4584 if (!xmlXPathIsNaN(v)) {
4585 if ((!neq) && (v==f)) {
4586 ret = 1;
4587 break;
4588 } else if ((neq) && (v!=f)) {
4589 ret = 1;
4590 break;
4591 }
William M. Brack32f0f712005-07-14 07:00:33 +00004592 } else { /* NaN is unequal to any value */
4593 if (neq)
4594 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00004595 }
4596 }
4597 }
4598 }
4599
4600 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004601}
4602
4603
4604/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004605 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004606 * @arg1: first nodeset object argument
4607 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004608 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004609 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004610 * Implement the equal / not equal operation on XPath nodesets:
4611 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004612 * If both objects to be compared are node-sets, then the comparison
4613 * will be true if and only if there is a node in the first node-set and
4614 * a node in the second node-set such that the result of performing the
4615 * comparison on the string-values of the two nodes is true.
4616 *
4617 * (needless to say, this is a costly operation)
4618 *
4619 * Returns 0 or 1 depending on the results of the test.
4620 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004621static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004622xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004623 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004624 unsigned int *hashs1;
4625 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004626 xmlChar **values1;
4627 xmlChar **values2;
4628 int ret = 0;
4629 xmlNodeSetPtr ns1;
4630 xmlNodeSetPtr ns2;
4631
4632 if ((arg1 == NULL) ||
4633 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4634 return(0);
4635 if ((arg2 == NULL) ||
4636 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4637 return(0);
4638
4639 ns1 = arg1->nodesetval;
4640 ns2 = arg2->nodesetval;
4641
Daniel Veillard911f49a2001-04-07 15:39:35 +00004642 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004643 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004644 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004645 return(0);
4646
4647 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004648 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004649 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004650 if (neq == 0)
4651 for (i = 0;i < ns1->nodeNr;i++)
4652 for (j = 0;j < ns2->nodeNr;j++)
4653 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4654 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004655
4656 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004657 if (values1 == NULL) {
4658 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004659 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004660 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004661 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4662 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004663 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004664 xmlFree(values1);
4665 return(0);
4666 }
Owen Taylor3473f882001-02-23 17:55:21 +00004667 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4668 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4669 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004670 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004671 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004672 xmlFree(values1);
4673 return(0);
4674 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004675 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4676 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004677 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004678 xmlFree(hashs1);
4679 xmlFree(values1);
4680 xmlFree(values2);
4681 return(0);
4682 }
Owen Taylor3473f882001-02-23 17:55:21 +00004683 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4684 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004685 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004686 for (j = 0;j < ns2->nodeNr;j++) {
4687 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004688 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004689 if (hashs1[i] != hashs2[j]) {
4690 if (neq) {
4691 ret = 1;
4692 break;
4693 }
4694 }
4695 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004696 if (values1[i] == NULL)
4697 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4698 if (values2[j] == NULL)
4699 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004700 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004701 if (ret)
4702 break;
4703 }
Owen Taylor3473f882001-02-23 17:55:21 +00004704 }
4705 if (ret)
4706 break;
4707 }
4708 for (i = 0;i < ns1->nodeNr;i++)
4709 if (values1[i] != NULL)
4710 xmlFree(values1[i]);
4711 for (j = 0;j < ns2->nodeNr;j++)
4712 if (values2[j] != NULL)
4713 xmlFree(values2[j]);
4714 xmlFree(values1);
4715 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004716 xmlFree(hashs1);
4717 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004718 return(ret);
4719}
4720
William M. Brack0c022ad2002-07-12 00:56:01 +00004721static int
4722xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4723 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004724 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004725 /*
4726 *At this point we are assured neither arg1 nor arg2
4727 *is a nodeset, so we can just pick the appropriate routine.
4728 */
Owen Taylor3473f882001-02-23 17:55:21 +00004729 switch (arg1->type) {
4730 case XPATH_UNDEFINED:
4731#ifdef DEBUG_EXPR
4732 xmlGenericError(xmlGenericErrorContext,
4733 "Equal: undefined\n");
4734#endif
4735 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004736 case XPATH_BOOLEAN:
4737 switch (arg2->type) {
4738 case XPATH_UNDEFINED:
4739#ifdef DEBUG_EXPR
4740 xmlGenericError(xmlGenericErrorContext,
4741 "Equal: undefined\n");
4742#endif
4743 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004744 case XPATH_BOOLEAN:
4745#ifdef DEBUG_EXPR
4746 xmlGenericError(xmlGenericErrorContext,
4747 "Equal: %d boolean %d \n",
4748 arg1->boolval, arg2->boolval);
4749#endif
4750 ret = (arg1->boolval == arg2->boolval);
4751 break;
4752 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004753 ret = (arg1->boolval ==
4754 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004755 break;
4756 case XPATH_STRING:
4757 if ((arg2->stringval == NULL) ||
4758 (arg2->stringval[0] == 0)) ret = 0;
4759 else
4760 ret = 1;
4761 ret = (arg1->boolval == ret);
4762 break;
4763 case XPATH_USERS:
4764 case XPATH_POINT:
4765 case XPATH_RANGE:
4766 case XPATH_LOCATIONSET:
4767 TODO
4768 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004769 case XPATH_NODESET:
4770 case XPATH_XSLT_TREE:
4771 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004772 }
4773 break;
4774 case XPATH_NUMBER:
4775 switch (arg2->type) {
4776 case XPATH_UNDEFINED:
4777#ifdef DEBUG_EXPR
4778 xmlGenericError(xmlGenericErrorContext,
4779 "Equal: undefined\n");
4780#endif
4781 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004782 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004783 ret = (arg2->boolval==
4784 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004785 break;
4786 case XPATH_STRING:
4787 valuePush(ctxt, arg2);
4788 xmlXPathNumberFunction(ctxt, 1);
4789 arg2 = valuePop(ctxt);
4790 /* no break on purpose */
4791 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004792 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004793 if (xmlXPathIsNaN(arg1->floatval) ||
4794 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004795 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004796 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4797 if (xmlXPathIsInf(arg2->floatval) == 1)
4798 ret = 1;
4799 else
4800 ret = 0;
4801 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4802 if (xmlXPathIsInf(arg2->floatval) == -1)
4803 ret = 1;
4804 else
4805 ret = 0;
4806 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4807 if (xmlXPathIsInf(arg1->floatval) == 1)
4808 ret = 1;
4809 else
4810 ret = 0;
4811 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4812 if (xmlXPathIsInf(arg1->floatval) == -1)
4813 ret = 1;
4814 else
4815 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004816 } else {
4817 ret = (arg1->floatval == arg2->floatval);
4818 }
Owen Taylor3473f882001-02-23 17:55:21 +00004819 break;
4820 case XPATH_USERS:
4821 case XPATH_POINT:
4822 case XPATH_RANGE:
4823 case XPATH_LOCATIONSET:
4824 TODO
4825 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004826 case XPATH_NODESET:
4827 case XPATH_XSLT_TREE:
4828 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004829 }
4830 break;
4831 case XPATH_STRING:
4832 switch (arg2->type) {
4833 case XPATH_UNDEFINED:
4834#ifdef DEBUG_EXPR
4835 xmlGenericError(xmlGenericErrorContext,
4836 "Equal: undefined\n");
4837#endif
4838 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004839 case XPATH_BOOLEAN:
4840 if ((arg1->stringval == NULL) ||
4841 (arg1->stringval[0] == 0)) ret = 0;
4842 else
4843 ret = 1;
4844 ret = (arg2->boolval == ret);
4845 break;
4846 case XPATH_STRING:
4847 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4848 break;
4849 case XPATH_NUMBER:
4850 valuePush(ctxt, arg1);
4851 xmlXPathNumberFunction(ctxt, 1);
4852 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004853 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004854 if (xmlXPathIsNaN(arg1->floatval) ||
4855 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004856 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004857 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4858 if (xmlXPathIsInf(arg2->floatval) == 1)
4859 ret = 1;
4860 else
4861 ret = 0;
4862 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4863 if (xmlXPathIsInf(arg2->floatval) == -1)
4864 ret = 1;
4865 else
4866 ret = 0;
4867 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4868 if (xmlXPathIsInf(arg1->floatval) == 1)
4869 ret = 1;
4870 else
4871 ret = 0;
4872 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4873 if (xmlXPathIsInf(arg1->floatval) == -1)
4874 ret = 1;
4875 else
4876 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004877 } else {
4878 ret = (arg1->floatval == arg2->floatval);
4879 }
Owen Taylor3473f882001-02-23 17:55:21 +00004880 break;
4881 case XPATH_USERS:
4882 case XPATH_POINT:
4883 case XPATH_RANGE:
4884 case XPATH_LOCATIONSET:
4885 TODO
4886 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004887 case XPATH_NODESET:
4888 case XPATH_XSLT_TREE:
4889 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004890 }
4891 break;
4892 case XPATH_USERS:
4893 case XPATH_POINT:
4894 case XPATH_RANGE:
4895 case XPATH_LOCATIONSET:
4896 TODO
4897 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004898 case XPATH_NODESET:
4899 case XPATH_XSLT_TREE:
4900 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004901 }
4902 xmlXPathFreeObject(arg1);
4903 xmlXPathFreeObject(arg2);
4904 return(ret);
4905}
4906
William M. Brack0c022ad2002-07-12 00:56:01 +00004907/**
4908 * xmlXPathEqualValues:
4909 * @ctxt: the XPath Parser context
4910 *
4911 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4912 *
4913 * Returns 0 or 1 depending on the results of the test.
4914 */
4915int
4916xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4917 xmlXPathObjectPtr arg1, arg2, argtmp;
4918 int ret = 0;
4919
Daniel Veillard6128c012004-11-08 17:16:15 +00004920 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00004921 arg2 = valuePop(ctxt);
4922 arg1 = valuePop(ctxt);
4923 if ((arg1 == NULL) || (arg2 == NULL)) {
4924 if (arg1 != NULL)
4925 xmlXPathFreeObject(arg1);
4926 else
4927 xmlXPathFreeObject(arg2);
4928 XP_ERROR0(XPATH_INVALID_OPERAND);
4929 }
4930
4931 if (arg1 == arg2) {
4932#ifdef DEBUG_EXPR
4933 xmlGenericError(xmlGenericErrorContext,
4934 "Equal: by pointer\n");
4935#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00004936 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004937 return(1);
4938 }
4939
4940 /*
4941 *If either argument is a nodeset, it's a 'special case'
4942 */
4943 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4944 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4945 /*
4946 *Hack it to assure arg1 is the nodeset
4947 */
4948 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4949 argtmp = arg2;
4950 arg2 = arg1;
4951 arg1 = argtmp;
4952 }
4953 switch (arg2->type) {
4954 case XPATH_UNDEFINED:
4955#ifdef DEBUG_EXPR
4956 xmlGenericError(xmlGenericErrorContext,
4957 "Equal: undefined\n");
4958#endif
4959 break;
4960 case XPATH_NODESET:
4961 case XPATH_XSLT_TREE:
4962 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4963 break;
4964 case XPATH_BOOLEAN:
4965 if ((arg1->nodesetval == NULL) ||
4966 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4967 else
4968 ret = 1;
4969 ret = (ret == arg2->boolval);
4970 break;
4971 case XPATH_NUMBER:
4972 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4973 break;
4974 case XPATH_STRING:
4975 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4976 break;
4977 case XPATH_USERS:
4978 case XPATH_POINT:
4979 case XPATH_RANGE:
4980 case XPATH_LOCATIONSET:
4981 TODO
4982 break;
4983 }
4984 xmlXPathFreeObject(arg1);
4985 xmlXPathFreeObject(arg2);
4986 return(ret);
4987 }
4988
4989 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4990}
4991
4992/**
4993 * xmlXPathNotEqualValues:
4994 * @ctxt: the XPath Parser context
4995 *
4996 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4997 *
4998 * Returns 0 or 1 depending on the results of the test.
4999 */
5000int
5001xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
5002 xmlXPathObjectPtr arg1, arg2, argtmp;
5003 int ret = 0;
5004
Daniel Veillard6128c012004-11-08 17:16:15 +00005005 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005006 arg2 = valuePop(ctxt);
5007 arg1 = valuePop(ctxt);
5008 if ((arg1 == NULL) || (arg2 == NULL)) {
5009 if (arg1 != NULL)
5010 xmlXPathFreeObject(arg1);
5011 else
5012 xmlXPathFreeObject(arg2);
5013 XP_ERROR0(XPATH_INVALID_OPERAND);
5014 }
5015
5016 if (arg1 == arg2) {
5017#ifdef DEBUG_EXPR
5018 xmlGenericError(xmlGenericErrorContext,
5019 "NotEqual: by pointer\n");
5020#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00005021 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00005022 return(0);
5023 }
5024
5025 /*
5026 *If either argument is a nodeset, it's a 'special case'
5027 */
5028 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5029 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5030 /*
5031 *Hack it to assure arg1 is the nodeset
5032 */
5033 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5034 argtmp = arg2;
5035 arg2 = arg1;
5036 arg1 = argtmp;
5037 }
5038 switch (arg2->type) {
5039 case XPATH_UNDEFINED:
5040#ifdef DEBUG_EXPR
5041 xmlGenericError(xmlGenericErrorContext,
5042 "NotEqual: undefined\n");
5043#endif
5044 break;
5045 case XPATH_NODESET:
5046 case XPATH_XSLT_TREE:
5047 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
5048 break;
5049 case XPATH_BOOLEAN:
5050 if ((arg1->nodesetval == NULL) ||
5051 (arg1->nodesetval->nodeNr == 0)) ret = 0;
5052 else
5053 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00005054 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00005055 break;
5056 case XPATH_NUMBER:
5057 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5058 break;
5059 case XPATH_STRING:
5060 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
5061 break;
5062 case XPATH_USERS:
5063 case XPATH_POINT:
5064 case XPATH_RANGE:
5065 case XPATH_LOCATIONSET:
5066 TODO
5067 break;
5068 }
5069 xmlXPathFreeObject(arg1);
5070 xmlXPathFreeObject(arg2);
5071 return(ret);
5072 }
5073
5074 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5075}
Owen Taylor3473f882001-02-23 17:55:21 +00005076
5077/**
5078 * xmlXPathCompareValues:
5079 * @ctxt: the XPath Parser context
5080 * @inf: less than (1) or greater than (0)
5081 * @strict: is the comparison strict
5082 *
5083 * Implement the compare operation on XPath objects:
5084 * @arg1 < @arg2 (1, 1, ...
5085 * @arg1 <= @arg2 (1, 0, ...
5086 * @arg1 > @arg2 (0, 1, ...
5087 * @arg1 >= @arg2 (0, 0, ...
5088 *
5089 * When neither object to be compared is a node-set and the operator is
5090 * <=, <, >=, >, then the objects are compared by converted both objects
5091 * to numbers and comparing the numbers according to IEEE 754. The <
5092 * comparison will be true if and only if the first number is less than the
5093 * second number. The <= comparison will be true if and only if the first
5094 * number is less than or equal to the second number. The > comparison
5095 * will be true if and only if the first number is greater than the second
5096 * number. The >= comparison will be true if and only if the first number
5097 * is greater than or equal to the second number.
5098 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005099 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005100 */
5101int
5102xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005103 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005104 xmlXPathObjectPtr arg1, arg2;
5105
Daniel Veillard6128c012004-11-08 17:16:15 +00005106 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005107 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005108 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005109 if ((arg1 == NULL) || (arg2 == NULL)) {
5110 if (arg1 != NULL)
5111 xmlXPathFreeObject(arg1);
5112 else
5113 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005114 XP_ERROR0(XPATH_INVALID_OPERAND);
5115 }
5116
William M. Brack0c022ad2002-07-12 00:56:01 +00005117 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5118 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00005119 /*
5120 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
5121 * are not freed from within this routine; they will be freed from the
5122 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
5123 */
William M. Brack0c022ad2002-07-12 00:56:01 +00005124 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5125 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005126 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005127 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005128 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005129 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5130 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005131 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005132 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5133 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005134 }
5135 }
5136 return(ret);
5137 }
5138
5139 if (arg1->type != XPATH_NUMBER) {
5140 valuePush(ctxt, arg1);
5141 xmlXPathNumberFunction(ctxt, 1);
5142 arg1 = valuePop(ctxt);
5143 }
5144 if (arg1->type != XPATH_NUMBER) {
5145 xmlXPathFreeObject(arg1);
5146 xmlXPathFreeObject(arg2);
5147 XP_ERROR0(XPATH_INVALID_OPERAND);
5148 }
5149 if (arg2->type != XPATH_NUMBER) {
5150 valuePush(ctxt, arg2);
5151 xmlXPathNumberFunction(ctxt, 1);
5152 arg2 = valuePop(ctxt);
5153 }
5154 if (arg2->type != XPATH_NUMBER) {
5155 xmlXPathFreeObject(arg1);
5156 xmlXPathFreeObject(arg2);
5157 XP_ERROR0(XPATH_INVALID_OPERAND);
5158 }
5159 /*
5160 * Add tests for infinity and nan
5161 * => feedback on 3.4 for Inf and NaN
5162 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005163 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005164 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005165 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005166 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005167 arg1i=xmlXPathIsInf(arg1->floatval);
5168 arg2i=xmlXPathIsInf(arg2->floatval);
5169 if (inf && strict) {
5170 if ((arg1i == -1 && arg2i != -1) ||
5171 (arg2i == 1 && arg1i != 1)) {
5172 ret = 1;
5173 } else if (arg1i == 0 && arg2i == 0) {
5174 ret = (arg1->floatval < arg2->floatval);
5175 } else {
5176 ret = 0;
5177 }
5178 }
5179 else if (inf && !strict) {
5180 if (arg1i == -1 || arg2i == 1) {
5181 ret = 1;
5182 } else if (arg1i == 0 && arg2i == 0) {
5183 ret = (arg1->floatval <= arg2->floatval);
5184 } else {
5185 ret = 0;
5186 }
5187 }
5188 else if (!inf && strict) {
5189 if ((arg1i == 1 && arg2i != 1) ||
5190 (arg2i == -1 && arg1i != -1)) {
5191 ret = 1;
5192 } else if (arg1i == 0 && arg2i == 0) {
5193 ret = (arg1->floatval > arg2->floatval);
5194 } else {
5195 ret = 0;
5196 }
5197 }
5198 else if (!inf && !strict) {
5199 if (arg1i == 1 || arg2i == -1) {
5200 ret = 1;
5201 } else if (arg1i == 0 && arg2i == 0) {
5202 ret = (arg1->floatval >= arg2->floatval);
5203 } else {
5204 ret = 0;
5205 }
5206 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005207 }
Owen Taylor3473f882001-02-23 17:55:21 +00005208 xmlXPathFreeObject(arg1);
5209 xmlXPathFreeObject(arg2);
5210 return(ret);
5211}
5212
5213/**
5214 * xmlXPathValueFlipSign:
5215 * @ctxt: the XPath Parser context
5216 *
5217 * Implement the unary - operation on an XPath object
5218 * The numeric operators convert their operands to numbers as if
5219 * by calling the number function.
5220 */
5221void
5222xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005223 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005224 CAST_TO_NUMBER;
5225 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005226 if (xmlXPathIsNaN(ctxt->value->floatval))
5227 ctxt->value->floatval=xmlXPathNAN;
5228 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5229 ctxt->value->floatval=xmlXPathNINF;
5230 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5231 ctxt->value->floatval=xmlXPathPINF;
5232 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005233 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5234 ctxt->value->floatval = xmlXPathNZERO;
5235 else
5236 ctxt->value->floatval = 0;
5237 }
5238 else
5239 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005240}
5241
5242/**
5243 * xmlXPathAddValues:
5244 * @ctxt: the XPath Parser context
5245 *
5246 * Implement the add operation on XPath objects:
5247 * The numeric operators convert their operands to numbers as if
5248 * by calling the number function.
5249 */
5250void
5251xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5252 xmlXPathObjectPtr arg;
5253 double val;
5254
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005255 arg = valuePop(ctxt);
5256 if (arg == NULL)
5257 XP_ERROR(XPATH_INVALID_OPERAND);
5258 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005259 xmlXPathFreeObject(arg);
5260
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005261 CAST_TO_NUMBER;
5262 CHECK_TYPE(XPATH_NUMBER);
5263 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005264}
5265
5266/**
5267 * xmlXPathSubValues:
5268 * @ctxt: the XPath Parser context
5269 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005270 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005271 * The numeric operators convert their operands to numbers as if
5272 * by calling the number function.
5273 */
5274void
5275xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5276 xmlXPathObjectPtr arg;
5277 double val;
5278
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005279 arg = valuePop(ctxt);
5280 if (arg == NULL)
5281 XP_ERROR(XPATH_INVALID_OPERAND);
5282 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005283 xmlXPathFreeObject(arg);
5284
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005285 CAST_TO_NUMBER;
5286 CHECK_TYPE(XPATH_NUMBER);
5287 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005288}
5289
5290/**
5291 * xmlXPathMultValues:
5292 * @ctxt: the XPath Parser context
5293 *
5294 * Implement the multiply operation on XPath objects:
5295 * The numeric operators convert their operands to numbers as if
5296 * by calling the number function.
5297 */
5298void
5299xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5300 xmlXPathObjectPtr arg;
5301 double val;
5302
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005303 arg = valuePop(ctxt);
5304 if (arg == NULL)
5305 XP_ERROR(XPATH_INVALID_OPERAND);
5306 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005307 xmlXPathFreeObject(arg);
5308
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005309 CAST_TO_NUMBER;
5310 CHECK_TYPE(XPATH_NUMBER);
5311 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005312}
5313
5314/**
5315 * xmlXPathDivValues:
5316 * @ctxt: the XPath Parser context
5317 *
5318 * Implement the div operation on XPath objects @arg1 / @arg2:
5319 * The numeric operators convert their operands to numbers as if
5320 * by calling the number function.
5321 */
5322void
5323xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5324 xmlXPathObjectPtr arg;
5325 double val;
5326
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005327 arg = valuePop(ctxt);
5328 if (arg == NULL)
5329 XP_ERROR(XPATH_INVALID_OPERAND);
5330 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005331 xmlXPathFreeObject(arg);
5332
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005333 CAST_TO_NUMBER;
5334 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005335 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5336 ctxt->value->floatval = xmlXPathNAN;
5337 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005338 if (ctxt->value->floatval == 0)
5339 ctxt->value->floatval = xmlXPathNAN;
5340 else if (ctxt->value->floatval > 0)
5341 ctxt->value->floatval = xmlXPathNINF;
5342 else if (ctxt->value->floatval < 0)
5343 ctxt->value->floatval = xmlXPathPINF;
5344 }
5345 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005346 if (ctxt->value->floatval == 0)
5347 ctxt->value->floatval = xmlXPathNAN;
5348 else if (ctxt->value->floatval > 0)
5349 ctxt->value->floatval = xmlXPathPINF;
5350 else if (ctxt->value->floatval < 0)
5351 ctxt->value->floatval = xmlXPathNINF;
5352 } else
5353 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005354}
5355
5356/**
5357 * xmlXPathModValues:
5358 * @ctxt: the XPath Parser context
5359 *
5360 * Implement the mod operation on XPath objects: @arg1 / @arg2
5361 * The numeric operators convert their operands to numbers as if
5362 * by calling the number function.
5363 */
5364void
5365xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5366 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005367 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005368
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005369 arg = valuePop(ctxt);
5370 if (arg == NULL)
5371 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005372 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005373 xmlXPathFreeObject(arg);
5374
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005375 CAST_TO_NUMBER;
5376 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005377 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005378 if (arg2 == 0)
5379 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005380 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005381 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005382 }
Owen Taylor3473f882001-02-23 17:55:21 +00005383}
5384
5385/************************************************************************
5386 * *
5387 * The traversal functions *
5388 * *
5389 ************************************************************************/
5390
Owen Taylor3473f882001-02-23 17:55:21 +00005391/*
5392 * A traversal function enumerates nodes along an axis.
5393 * Initially it must be called with NULL, and it indicates
5394 * termination on the axis by returning NULL.
5395 */
5396typedef xmlNodePtr (*xmlXPathTraversalFunction)
5397 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5398
5399/**
5400 * xmlXPathNextSelf:
5401 * @ctxt: the XPath Parser context
5402 * @cur: the current node in the traversal
5403 *
5404 * Traversal function for the "self" direction
5405 * The self axis contains just the context node itself
5406 *
5407 * Returns the next element following that axis
5408 */
5409xmlNodePtr
5410xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005411 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005412 if (cur == NULL)
5413 return(ctxt->context->node);
5414 return(NULL);
5415}
5416
5417/**
5418 * xmlXPathNextChild:
5419 * @ctxt: the XPath Parser context
5420 * @cur: the current node in the traversal
5421 *
5422 * Traversal function for the "child" direction
5423 * The child axis contains the children of the context node in document order.
5424 *
5425 * Returns the next element following that axis
5426 */
5427xmlNodePtr
5428xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005429 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005430 if (cur == NULL) {
5431 if (ctxt->context->node == NULL) return(NULL);
5432 switch (ctxt->context->node->type) {
5433 case XML_ELEMENT_NODE:
5434 case XML_TEXT_NODE:
5435 case XML_CDATA_SECTION_NODE:
5436 case XML_ENTITY_REF_NODE:
5437 case XML_ENTITY_NODE:
5438 case XML_PI_NODE:
5439 case XML_COMMENT_NODE:
5440 case XML_NOTATION_NODE:
5441 case XML_DTD_NODE:
5442 return(ctxt->context->node->children);
5443 case XML_DOCUMENT_NODE:
5444 case XML_DOCUMENT_TYPE_NODE:
5445 case XML_DOCUMENT_FRAG_NODE:
5446 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005447#ifdef LIBXML_DOCB_ENABLED
5448 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005449#endif
5450 return(((xmlDocPtr) ctxt->context->node)->children);
5451 case XML_ELEMENT_DECL:
5452 case XML_ATTRIBUTE_DECL:
5453 case XML_ENTITY_DECL:
5454 case XML_ATTRIBUTE_NODE:
5455 case XML_NAMESPACE_DECL:
5456 case XML_XINCLUDE_START:
5457 case XML_XINCLUDE_END:
5458 return(NULL);
5459 }
5460 return(NULL);
5461 }
5462 if ((cur->type == XML_DOCUMENT_NODE) ||
5463 (cur->type == XML_HTML_DOCUMENT_NODE))
5464 return(NULL);
5465 return(cur->next);
5466}
5467
5468/**
5469 * xmlXPathNextDescendant:
5470 * @ctxt: the XPath Parser context
5471 * @cur: the current node in the traversal
5472 *
5473 * Traversal function for the "descendant" direction
5474 * the descendant axis contains the descendants of the context node in document
5475 * order; a descendant is a child or a child of a child and so on.
5476 *
5477 * Returns the next element following that axis
5478 */
5479xmlNodePtr
5480xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005481 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005482 if (cur == NULL) {
5483 if (ctxt->context->node == NULL)
5484 return(NULL);
5485 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5486 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5487 return(NULL);
5488
5489 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5490 return(ctxt->context->doc->children);
5491 return(ctxt->context->node->children);
5492 }
5493
Daniel Veillard567e1b42001-08-01 15:53:47 +00005494 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005495 /*
5496 * Do not descend on entities declarations
5497 */
5498 if (cur->children->type != XML_ENTITY_DECL) {
5499 cur = cur->children;
5500 /*
5501 * Skip DTDs
5502 */
5503 if (cur->type != XML_DTD_NODE)
5504 return(cur);
5505 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005506 }
5507
5508 if (cur == ctxt->context->node) return(NULL);
5509
Daniel Veillard68e9e742002-11-16 15:35:11 +00005510 while (cur->next != NULL) {
5511 cur = cur->next;
5512 if ((cur->type != XML_ENTITY_DECL) &&
5513 (cur->type != XML_DTD_NODE))
5514 return(cur);
5515 }
Owen Taylor3473f882001-02-23 17:55:21 +00005516
5517 do {
5518 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00005519 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00005520 if (cur == ctxt->context->node) return(NULL);
5521 if (cur->next != NULL) {
5522 cur = cur->next;
5523 return(cur);
5524 }
5525 } while (cur != NULL);
5526 return(cur);
5527}
5528
5529/**
5530 * xmlXPathNextDescendantOrSelf:
5531 * @ctxt: the XPath Parser context
5532 * @cur: the current node in the traversal
5533 *
5534 * Traversal function for the "descendant-or-self" direction
5535 * the descendant-or-self axis contains the context node and the descendants
5536 * of the context node in document order; thus the context node is the first
5537 * node on the axis, and the first child of the context node is the second node
5538 * on the axis
5539 *
5540 * Returns the next element following that axis
5541 */
5542xmlNodePtr
5543xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005544 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005545 if (cur == NULL) {
5546 if (ctxt->context->node == NULL)
5547 return(NULL);
5548 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5549 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5550 return(NULL);
5551 return(ctxt->context->node);
5552 }
5553
5554 return(xmlXPathNextDescendant(ctxt, cur));
5555}
5556
5557/**
5558 * xmlXPathNextParent:
5559 * @ctxt: the XPath Parser context
5560 * @cur: the current node in the traversal
5561 *
5562 * Traversal function for the "parent" direction
5563 * The parent axis contains the parent of the context node, if there is one.
5564 *
5565 * Returns the next element following that axis
5566 */
5567xmlNodePtr
5568xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005569 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005570 /*
5571 * the parent of an attribute or namespace node is the element
5572 * to which the attribute or namespace node is attached
5573 * Namespace handling !!!
5574 */
5575 if (cur == NULL) {
5576 if (ctxt->context->node == NULL) return(NULL);
5577 switch (ctxt->context->node->type) {
5578 case XML_ELEMENT_NODE:
5579 case XML_TEXT_NODE:
5580 case XML_CDATA_SECTION_NODE:
5581 case XML_ENTITY_REF_NODE:
5582 case XML_ENTITY_NODE:
5583 case XML_PI_NODE:
5584 case XML_COMMENT_NODE:
5585 case XML_NOTATION_NODE:
5586 case XML_DTD_NODE:
5587 case XML_ELEMENT_DECL:
5588 case XML_ATTRIBUTE_DECL:
5589 case XML_XINCLUDE_START:
5590 case XML_XINCLUDE_END:
5591 case XML_ENTITY_DECL:
5592 if (ctxt->context->node->parent == NULL)
5593 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005594 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005595 ((ctxt->context->node->parent->name[0] == ' ') ||
5596 (xmlStrEqual(ctxt->context->node->parent->name,
5597 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005598 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005599 return(ctxt->context->node->parent);
5600 case XML_ATTRIBUTE_NODE: {
5601 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5602
5603 return(att->parent);
5604 }
5605 case XML_DOCUMENT_NODE:
5606 case XML_DOCUMENT_TYPE_NODE:
5607 case XML_DOCUMENT_FRAG_NODE:
5608 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005609#ifdef LIBXML_DOCB_ENABLED
5610 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005611#endif
5612 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005613 case XML_NAMESPACE_DECL: {
5614 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5615
5616 if ((ns->next != NULL) &&
5617 (ns->next->type != XML_NAMESPACE_DECL))
5618 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005619 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005620 }
Owen Taylor3473f882001-02-23 17:55:21 +00005621 }
5622 }
5623 return(NULL);
5624}
5625
5626/**
5627 * xmlXPathNextAncestor:
5628 * @ctxt: the XPath Parser context
5629 * @cur: the current node in the traversal
5630 *
5631 * Traversal function for the "ancestor" direction
5632 * the ancestor axis contains the ancestors of the context node; the ancestors
5633 * of the context node consist of the parent of context node and the parent's
5634 * parent and so on; the nodes are ordered in reverse document order; thus the
5635 * parent is the first node on the axis, and the parent's parent is the second
5636 * node on the axis
5637 *
5638 * Returns the next element following that axis
5639 */
5640xmlNodePtr
5641xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005642 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005643 /*
5644 * the parent of an attribute or namespace node is the element
5645 * to which the attribute or namespace node is attached
5646 * !!!!!!!!!!!!!
5647 */
5648 if (cur == NULL) {
5649 if (ctxt->context->node == NULL) return(NULL);
5650 switch (ctxt->context->node->type) {
5651 case XML_ELEMENT_NODE:
5652 case XML_TEXT_NODE:
5653 case XML_CDATA_SECTION_NODE:
5654 case XML_ENTITY_REF_NODE:
5655 case XML_ENTITY_NODE:
5656 case XML_PI_NODE:
5657 case XML_COMMENT_NODE:
5658 case XML_DTD_NODE:
5659 case XML_ELEMENT_DECL:
5660 case XML_ATTRIBUTE_DECL:
5661 case XML_ENTITY_DECL:
5662 case XML_NOTATION_NODE:
5663 case XML_XINCLUDE_START:
5664 case XML_XINCLUDE_END:
5665 if (ctxt->context->node->parent == NULL)
5666 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005667 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005668 ((ctxt->context->node->parent->name[0] == ' ') ||
5669 (xmlStrEqual(ctxt->context->node->parent->name,
5670 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005671 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005672 return(ctxt->context->node->parent);
5673 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005674 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005675
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005676 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005677 }
5678 case XML_DOCUMENT_NODE:
5679 case XML_DOCUMENT_TYPE_NODE:
5680 case XML_DOCUMENT_FRAG_NODE:
5681 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005682#ifdef LIBXML_DOCB_ENABLED
5683 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005684#endif
5685 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005686 case XML_NAMESPACE_DECL: {
5687 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5688
5689 if ((ns->next != NULL) &&
5690 (ns->next->type != XML_NAMESPACE_DECL))
5691 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005692 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005693 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005694 }
Owen Taylor3473f882001-02-23 17:55:21 +00005695 }
5696 return(NULL);
5697 }
5698 if (cur == ctxt->context->doc->children)
5699 return((xmlNodePtr) ctxt->context->doc);
5700 if (cur == (xmlNodePtr) ctxt->context->doc)
5701 return(NULL);
5702 switch (cur->type) {
5703 case XML_ELEMENT_NODE:
5704 case XML_TEXT_NODE:
5705 case XML_CDATA_SECTION_NODE:
5706 case XML_ENTITY_REF_NODE:
5707 case XML_ENTITY_NODE:
5708 case XML_PI_NODE:
5709 case XML_COMMENT_NODE:
5710 case XML_NOTATION_NODE:
5711 case XML_DTD_NODE:
5712 case XML_ELEMENT_DECL:
5713 case XML_ATTRIBUTE_DECL:
5714 case XML_ENTITY_DECL:
5715 case XML_XINCLUDE_START:
5716 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005717 if (cur->parent == NULL)
5718 return(NULL);
5719 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005720 ((cur->parent->name[0] == ' ') ||
5721 (xmlStrEqual(cur->parent->name,
5722 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005723 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005724 return(cur->parent);
5725 case XML_ATTRIBUTE_NODE: {
5726 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5727
5728 return(att->parent);
5729 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005730 case XML_NAMESPACE_DECL: {
5731 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5732
5733 if ((ns->next != NULL) &&
5734 (ns->next->type != XML_NAMESPACE_DECL))
5735 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005736 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005737 return(NULL);
5738 }
Owen Taylor3473f882001-02-23 17:55:21 +00005739 case XML_DOCUMENT_NODE:
5740 case XML_DOCUMENT_TYPE_NODE:
5741 case XML_DOCUMENT_FRAG_NODE:
5742 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005743#ifdef LIBXML_DOCB_ENABLED
5744 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005745#endif
5746 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005747 }
5748 return(NULL);
5749}
5750
5751/**
5752 * xmlXPathNextAncestorOrSelf:
5753 * @ctxt: the XPath Parser context
5754 * @cur: the current node in the traversal
5755 *
5756 * Traversal function for the "ancestor-or-self" direction
5757 * he ancestor-or-self axis contains the context node and ancestors of
5758 * the context node in reverse document order; thus the context node is
5759 * the first node on the axis, and the context node's parent the second;
5760 * parent here is defined the same as with the parent axis.
5761 *
5762 * Returns the next element following that axis
5763 */
5764xmlNodePtr
5765xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005766 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005767 if (cur == NULL)
5768 return(ctxt->context->node);
5769 return(xmlXPathNextAncestor(ctxt, cur));
5770}
5771
5772/**
5773 * xmlXPathNextFollowingSibling:
5774 * @ctxt: the XPath Parser context
5775 * @cur: the current node in the traversal
5776 *
5777 * Traversal function for the "following-sibling" direction
5778 * The following-sibling axis contains the following siblings of the context
5779 * node in document order.
5780 *
5781 * Returns the next element following that axis
5782 */
5783xmlNodePtr
5784xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005785 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005786 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5787 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5788 return(NULL);
5789 if (cur == (xmlNodePtr) ctxt->context->doc)
5790 return(NULL);
5791 if (cur == NULL)
5792 return(ctxt->context->node->next);
5793 return(cur->next);
5794}
5795
5796/**
5797 * xmlXPathNextPrecedingSibling:
5798 * @ctxt: the XPath Parser context
5799 * @cur: the current node in the traversal
5800 *
5801 * Traversal function for the "preceding-sibling" direction
5802 * The preceding-sibling axis contains the preceding siblings of the context
5803 * node in reverse document order; the first preceding sibling is first on the
5804 * axis; the sibling preceding that node is the second on the axis and so on.
5805 *
5806 * Returns the next element following that axis
5807 */
5808xmlNodePtr
5809xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005810 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005811 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5812 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5813 return(NULL);
5814 if (cur == (xmlNodePtr) ctxt->context->doc)
5815 return(NULL);
5816 if (cur == NULL)
5817 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005818 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5819 cur = cur->prev;
5820 if (cur == NULL)
5821 return(ctxt->context->node->prev);
5822 }
Owen Taylor3473f882001-02-23 17:55:21 +00005823 return(cur->prev);
5824}
5825
5826/**
5827 * xmlXPathNextFollowing:
5828 * @ctxt: the XPath Parser context
5829 * @cur: the current node in the traversal
5830 *
5831 * Traversal function for the "following" direction
5832 * The following axis contains all nodes in the same document as the context
5833 * node that are after the context node in document order, excluding any
5834 * descendants and excluding attribute nodes and namespace nodes; the nodes
5835 * are ordered in document order
5836 *
5837 * Returns the next element following that axis
5838 */
5839xmlNodePtr
5840xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005841 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005842 if (cur != NULL && cur->children != NULL)
5843 return cur->children ;
5844 if (cur == NULL) cur = ctxt->context->node;
5845 if (cur == NULL) return(NULL) ; /* ERROR */
5846 if (cur->next != NULL) return(cur->next) ;
5847 do {
5848 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00005849 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00005850 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5851 if (cur->next != NULL) return(cur->next);
5852 } while (cur != NULL);
5853 return(cur);
5854}
5855
5856/*
5857 * xmlXPathIsAncestor:
5858 * @ancestor: the ancestor node
5859 * @node: the current node
5860 *
5861 * Check that @ancestor is a @node's ancestor
5862 *
5863 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5864 */
5865static int
5866xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5867 if ((ancestor == NULL) || (node == NULL)) return(0);
5868 /* nodes need to be in the same document */
5869 if (ancestor->doc != node->doc) return(0);
5870 /* avoid searching if ancestor or node is the root node */
5871 if (ancestor == (xmlNodePtr) node->doc) return(1);
5872 if (node == (xmlNodePtr) ancestor->doc) return(0);
5873 while (node->parent != NULL) {
5874 if (node->parent == ancestor)
5875 return(1);
5876 node = node->parent;
5877 }
5878 return(0);
5879}
5880
5881/**
5882 * xmlXPathNextPreceding:
5883 * @ctxt: the XPath Parser context
5884 * @cur: the current node in the traversal
5885 *
5886 * Traversal function for the "preceding" direction
5887 * the preceding axis contains all nodes in the same document as the context
5888 * node that are before the context node in document order, excluding any
5889 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5890 * ordered in reverse document order
5891 *
5892 * Returns the next element following that axis
5893 */
5894xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005895xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5896{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005897 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005898 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005899 cur = ctxt->context->node;
5900 if (cur == NULL)
5901 return (NULL);
5902 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5903 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005904 do {
5905 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005906 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5907 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005908 }
5909
5910 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005911 if (cur == NULL)
5912 return (NULL);
5913 if (cur == ctxt->context->doc->children)
5914 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005915 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005916 return (cur);
5917}
5918
5919/**
5920 * xmlXPathNextPrecedingInternal:
5921 * @ctxt: the XPath Parser context
5922 * @cur: the current node in the traversal
5923 *
5924 * Traversal function for the "preceding" direction
5925 * the preceding axis contains all nodes in the same document as the context
5926 * node that are before the context node in document order, excluding any
5927 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5928 * ordered in reverse document order
5929 * This is a faster implementation but internal only since it requires a
5930 * state kept in the parser context: ctxt->ancestor.
5931 *
5932 * Returns the next element following that axis
5933 */
5934static xmlNodePtr
5935xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5936 xmlNodePtr cur)
5937{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005938 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005939 if (cur == NULL) {
5940 cur = ctxt->context->node;
5941 if (cur == NULL)
5942 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005943 if (cur->type == XML_NAMESPACE_DECL)
5944 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005945 ctxt->ancestor = cur->parent;
5946 }
5947 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5948 cur = cur->prev;
5949 while (cur->prev == NULL) {
5950 cur = cur->parent;
5951 if (cur == NULL)
5952 return (NULL);
5953 if (cur == ctxt->context->doc->children)
5954 return (NULL);
5955 if (cur != ctxt->ancestor)
5956 return (cur);
5957 ctxt->ancestor = cur->parent;
5958 }
5959 cur = cur->prev;
5960 while (cur->last != NULL)
5961 cur = cur->last;
5962 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005963}
5964
5965/**
5966 * xmlXPathNextNamespace:
5967 * @ctxt: the XPath Parser context
5968 * @cur: the current attribute in the traversal
5969 *
5970 * Traversal function for the "namespace" direction
5971 * the namespace axis contains the namespace nodes of the context node;
5972 * the order of nodes on this axis is implementation-defined; the axis will
5973 * be empty unless the context node is an element
5974 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005975 * We keep the XML namespace node at the end of the list.
5976 *
Owen Taylor3473f882001-02-23 17:55:21 +00005977 * Returns the next element following that axis
5978 */
5979xmlNodePtr
5980xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005981 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005982 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005983 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005984 if (ctxt->context->tmpNsList != NULL)
5985 xmlFree(ctxt->context->tmpNsList);
5986 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005987 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005988 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005989 if (ctxt->context->tmpNsList != NULL) {
5990 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5991 ctxt->context->tmpNsNr++;
5992 }
5993 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005994 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005995 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005996 if (ctxt->context->tmpNsNr > 0) {
5997 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5998 } else {
5999 if (ctxt->context->tmpNsList != NULL)
6000 xmlFree(ctxt->context->tmpNsList);
6001 ctxt->context->tmpNsList = NULL;
6002 return(NULL);
6003 }
Owen Taylor3473f882001-02-23 17:55:21 +00006004}
6005
6006/**
6007 * xmlXPathNextAttribute:
6008 * @ctxt: the XPath Parser context
6009 * @cur: the current attribute in the traversal
6010 *
6011 * Traversal function for the "attribute" direction
6012 * TODO: support DTD inherited default attributes
6013 *
6014 * Returns the next element following that axis
6015 */
6016xmlNodePtr
6017xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006018 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00006019 if (ctxt->context->node == NULL)
6020 return(NULL);
6021 if (ctxt->context->node->type != XML_ELEMENT_NODE)
6022 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006023 if (cur == NULL) {
6024 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6025 return(NULL);
6026 return((xmlNodePtr)ctxt->context->node->properties);
6027 }
6028 return((xmlNodePtr)cur->next);
6029}
6030
6031/************************************************************************
6032 * *
6033 * NodeTest Functions *
6034 * *
6035 ************************************************************************/
6036
Owen Taylor3473f882001-02-23 17:55:21 +00006037#define IS_FUNCTION 200
6038
Owen Taylor3473f882001-02-23 17:55:21 +00006039
6040/************************************************************************
6041 * *
6042 * Implicit tree core function library *
6043 * *
6044 ************************************************************************/
6045
6046/**
6047 * xmlXPathRoot:
6048 * @ctxt: the XPath Parser context
6049 *
6050 * Initialize the context to the root of the document
6051 */
6052void
6053xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006054 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006055 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
6056 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6057}
6058
6059/************************************************************************
6060 * *
6061 * The explicit core function library *
6062 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
6063 * *
6064 ************************************************************************/
6065
6066
6067/**
6068 * xmlXPathLastFunction:
6069 * @ctxt: the XPath Parser context
6070 * @nargs: the number of arguments
6071 *
6072 * Implement the last() XPath function
6073 * number last()
6074 * The last function returns the number of nodes in the context node list.
6075 */
6076void
6077xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6078 CHECK_ARITY(0);
6079 if (ctxt->context->contextSize >= 0) {
6080 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
6081#ifdef DEBUG_EXPR
6082 xmlGenericError(xmlGenericErrorContext,
6083 "last() : %d\n", ctxt->context->contextSize);
6084#endif
6085 } else {
6086 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6087 }
6088}
6089
6090/**
6091 * xmlXPathPositionFunction:
6092 * @ctxt: the XPath Parser context
6093 * @nargs: the number of arguments
6094 *
6095 * Implement the position() XPath function
6096 * number position()
6097 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006098 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00006099 * will be equal to last().
6100 */
6101void
6102xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6103 CHECK_ARITY(0);
6104 if (ctxt->context->proximityPosition >= 0) {
6105 valuePush(ctxt,
6106 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6107#ifdef DEBUG_EXPR
6108 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6109 ctxt->context->proximityPosition);
6110#endif
6111 } else {
6112 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6113 }
6114}
6115
6116/**
6117 * xmlXPathCountFunction:
6118 * @ctxt: the XPath Parser context
6119 * @nargs: the number of arguments
6120 *
6121 * Implement the count() XPath function
6122 * number count(node-set)
6123 */
6124void
6125xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6126 xmlXPathObjectPtr cur;
6127
6128 CHECK_ARITY(1);
6129 if ((ctxt->value == NULL) ||
6130 ((ctxt->value->type != XPATH_NODESET) &&
6131 (ctxt->value->type != XPATH_XSLT_TREE)))
6132 XP_ERROR(XPATH_INVALID_TYPE);
6133 cur = valuePop(ctxt);
6134
Daniel Veillard911f49a2001-04-07 15:39:35 +00006135 if ((cur == NULL) || (cur->nodesetval == NULL))
6136 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006137 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006138 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006139 } else {
6140 if ((cur->nodesetval->nodeNr != 1) ||
6141 (cur->nodesetval->nodeTab == NULL)) {
6142 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6143 } else {
6144 xmlNodePtr tmp;
6145 int i = 0;
6146
6147 tmp = cur->nodesetval->nodeTab[0];
6148 if (tmp != NULL) {
6149 tmp = tmp->children;
6150 while (tmp != NULL) {
6151 tmp = tmp->next;
6152 i++;
6153 }
6154 }
6155 valuePush(ctxt, xmlXPathNewFloat((double) i));
6156 }
6157 }
Owen Taylor3473f882001-02-23 17:55:21 +00006158 xmlXPathFreeObject(cur);
6159}
6160
6161/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006162 * xmlXPathGetElementsByIds:
6163 * @doc: the document
6164 * @ids: a whitespace separated list of IDs
6165 *
6166 * Selects elements by their unique ID.
6167 *
6168 * Returns a node-set of selected elements.
6169 */
6170static xmlNodeSetPtr
6171xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6172 xmlNodeSetPtr ret;
6173 const xmlChar *cur = ids;
6174 xmlChar *ID;
6175 xmlAttrPtr attr;
6176 xmlNodePtr elem = NULL;
6177
Daniel Veillard7a985a12003-07-06 17:57:42 +00006178 if (ids == NULL) return(NULL);
6179
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006180 ret = xmlXPathNodeSetCreate(NULL);
6181
William M. Brack76e95df2003-10-18 16:20:14 +00006182 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006183 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006184 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006185 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006186
6187 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006188 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00006189 /*
6190 * We used to check the fact that the value passed
6191 * was an NCName, but this generated much troubles for
6192 * me and Aleksey Sanin, people blatantly violated that
6193 * constaint, like Visa3D spec.
6194 * if (xmlValidateNCName(ID, 1) == 0)
6195 */
6196 attr = xmlGetID(doc, ID);
6197 if (attr != NULL) {
6198 if (attr->type == XML_ATTRIBUTE_NODE)
6199 elem = attr->parent;
6200 else if (attr->type == XML_ELEMENT_NODE)
6201 elem = (xmlNodePtr) attr;
6202 else
6203 elem = NULL;
6204 if (elem != NULL)
6205 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00006206 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006207 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006208 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006209
William M. Brack76e95df2003-10-18 16:20:14 +00006210 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006211 ids = cur;
6212 }
6213 return(ret);
6214}
6215
6216/**
Owen Taylor3473f882001-02-23 17:55:21 +00006217 * xmlXPathIdFunction:
6218 * @ctxt: the XPath Parser context
6219 * @nargs: the number of arguments
6220 *
6221 * Implement the id() XPath function
6222 * node-set id(object)
6223 * The id function selects elements by their unique ID
6224 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6225 * then the result is the union of the result of applying id to the
6226 * string value of each of the nodes in the argument node-set. When the
6227 * argument to id is of any other type, the argument is converted to a
6228 * string as if by a call to the string function; the string is split
6229 * into a whitespace-separated list of tokens (whitespace is any sequence
6230 * of characters matching the production S); the result is a node-set
6231 * containing the elements in the same document as the context node that
6232 * have a unique ID equal to any of the tokens in the list.
6233 */
6234void
6235xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006236 xmlChar *tokens;
6237 xmlNodeSetPtr ret;
6238 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006239
6240 CHECK_ARITY(1);
6241 obj = valuePop(ctxt);
6242 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006243 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006244 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006245 int i;
6246
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006247 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006248
Daniel Veillard911f49a2001-04-07 15:39:35 +00006249 if (obj->nodesetval != NULL) {
6250 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006251 tokens =
6252 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6253 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6254 ret = xmlXPathNodeSetMerge(ret, ns);
6255 xmlXPathFreeNodeSet(ns);
6256 if (tokens != NULL)
6257 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006258 }
Owen Taylor3473f882001-02-23 17:55:21 +00006259 }
6260
6261 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006262 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006263 return;
6264 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006265 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006266
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006267 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6268 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006269
Owen Taylor3473f882001-02-23 17:55:21 +00006270 xmlXPathFreeObject(obj);
6271 return;
6272}
6273
6274/**
6275 * xmlXPathLocalNameFunction:
6276 * @ctxt: the XPath Parser context
6277 * @nargs: the number of arguments
6278 *
6279 * Implement the local-name() XPath function
6280 * string local-name(node-set?)
6281 * The local-name function returns a string containing the local part
6282 * of the name of the node in the argument node-set that is first in
6283 * document order. If the node-set is empty or the first node has no
6284 * name, an empty string is returned. If the argument is omitted it
6285 * defaults to the context node.
6286 */
6287void
6288xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6289 xmlXPathObjectPtr cur;
6290
Daniel Veillarda82b1822004-11-08 16:24:57 +00006291 if (ctxt == NULL) return;
6292
Owen Taylor3473f882001-02-23 17:55:21 +00006293 if (nargs == 0) {
6294 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6295 nargs = 1;
6296 }
6297
6298 CHECK_ARITY(1);
6299 if ((ctxt->value == NULL) ||
6300 ((ctxt->value->type != XPATH_NODESET) &&
6301 (ctxt->value->type != XPATH_XSLT_TREE)))
6302 XP_ERROR(XPATH_INVALID_TYPE);
6303 cur = valuePop(ctxt);
6304
Daniel Veillard911f49a2001-04-07 15:39:35 +00006305 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006306 valuePush(ctxt, xmlXPathNewCString(""));
6307 } else {
6308 int i = 0; /* Should be first in document order !!!!! */
6309 switch (cur->nodesetval->nodeTab[i]->type) {
6310 case XML_ELEMENT_NODE:
6311 case XML_ATTRIBUTE_NODE:
6312 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006313 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6314 valuePush(ctxt, xmlXPathNewCString(""));
6315 else
6316 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006317 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6318 break;
6319 case XML_NAMESPACE_DECL:
6320 valuePush(ctxt, xmlXPathNewString(
6321 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6322 break;
6323 default:
6324 valuePush(ctxt, xmlXPathNewCString(""));
6325 }
6326 }
6327 xmlXPathFreeObject(cur);
6328}
6329
6330/**
6331 * xmlXPathNamespaceURIFunction:
6332 * @ctxt: the XPath Parser context
6333 * @nargs: the number of arguments
6334 *
6335 * Implement the namespace-uri() XPath function
6336 * string namespace-uri(node-set?)
6337 * The namespace-uri function returns a string containing the
6338 * namespace URI of the expanded name of the node in the argument
6339 * node-set that is first in document order. If the node-set is empty,
6340 * the first node has no name, or the expanded name has no namespace
6341 * URI, an empty string is returned. If the argument is omitted it
6342 * defaults to the context node.
6343 */
6344void
6345xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6346 xmlXPathObjectPtr cur;
6347
Daniel Veillarda82b1822004-11-08 16:24:57 +00006348 if (ctxt == NULL) return;
6349
Owen Taylor3473f882001-02-23 17:55:21 +00006350 if (nargs == 0) {
6351 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6352 nargs = 1;
6353 }
6354 CHECK_ARITY(1);
6355 if ((ctxt->value == NULL) ||
6356 ((ctxt->value->type != XPATH_NODESET) &&
6357 (ctxt->value->type != XPATH_XSLT_TREE)))
6358 XP_ERROR(XPATH_INVALID_TYPE);
6359 cur = valuePop(ctxt);
6360
Daniel Veillard911f49a2001-04-07 15:39:35 +00006361 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006362 valuePush(ctxt, xmlXPathNewCString(""));
6363 } else {
6364 int i = 0; /* Should be first in document order !!!!! */
6365 switch (cur->nodesetval->nodeTab[i]->type) {
6366 case XML_ELEMENT_NODE:
6367 case XML_ATTRIBUTE_NODE:
6368 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6369 valuePush(ctxt, xmlXPathNewCString(""));
6370 else
6371 valuePush(ctxt, xmlXPathNewString(
6372 cur->nodesetval->nodeTab[i]->ns->href));
6373 break;
6374 default:
6375 valuePush(ctxt, xmlXPathNewCString(""));
6376 }
6377 }
6378 xmlXPathFreeObject(cur);
6379}
6380
6381/**
6382 * xmlXPathNameFunction:
6383 * @ctxt: the XPath Parser context
6384 * @nargs: the number of arguments
6385 *
6386 * Implement the name() XPath function
6387 * string name(node-set?)
6388 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006389 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006390 * order. The QName must represent the name with respect to the namespace
6391 * declarations in effect on the node whose name is being represented.
6392 * Typically, this will be the form in which the name occurred in the XML
6393 * source. This need not be the case if there are namespace declarations
6394 * in effect on the node that associate multiple prefixes with the same
6395 * namespace. However, an implementation may include information about
6396 * the original prefix in its representation of nodes; in this case, an
6397 * implementation can ensure that the returned string is always the same
6398 * as the QName used in the XML source. If the argument it omitted it
6399 * defaults to the context node.
6400 * Libxml keep the original prefix so the "real qualified name" used is
6401 * returned.
6402 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006403static void
Daniel Veillard04383752001-07-08 14:27:15 +00006404xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6405{
Owen Taylor3473f882001-02-23 17:55:21 +00006406 xmlXPathObjectPtr cur;
6407
6408 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006409 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6410 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006411 }
6412
6413 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006414 if ((ctxt->value == NULL) ||
6415 ((ctxt->value->type != XPATH_NODESET) &&
6416 (ctxt->value->type != XPATH_XSLT_TREE)))
6417 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006418 cur = valuePop(ctxt);
6419
Daniel Veillard911f49a2001-04-07 15:39:35 +00006420 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006421 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006422 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006423 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006424
Daniel Veillard04383752001-07-08 14:27:15 +00006425 switch (cur->nodesetval->nodeTab[i]->type) {
6426 case XML_ELEMENT_NODE:
6427 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006428 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6429 valuePush(ctxt, xmlXPathNewCString(""));
6430 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6431 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006432 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006433 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006434
Daniel Veillard652d8a92003-02-04 19:28:49 +00006435 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006436 xmlChar *fullname;
6437
6438 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6439 cur->nodesetval->nodeTab[i]->ns->prefix,
6440 NULL, 0);
6441 if (fullname == cur->nodesetval->nodeTab[i]->name)
6442 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6443 if (fullname == NULL) {
6444 XP_ERROR(XPATH_MEMORY_ERROR);
6445 }
6446 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006447 }
6448 break;
6449 default:
6450 valuePush(ctxt,
6451 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6452 xmlXPathLocalNameFunction(ctxt, 1);
6453 }
Owen Taylor3473f882001-02-23 17:55:21 +00006454 }
6455 xmlXPathFreeObject(cur);
6456}
6457
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006458
6459/**
Owen Taylor3473f882001-02-23 17:55:21 +00006460 * xmlXPathStringFunction:
6461 * @ctxt: the XPath Parser context
6462 * @nargs: the number of arguments
6463 *
6464 * Implement the string() XPath function
6465 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006466 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006467 * - A node-set is converted to a string by returning the value of
6468 * the node in the node-set that is first in document order.
6469 * If the node-set is empty, an empty string is returned.
6470 * - A number is converted to a string as follows
6471 * + NaN is converted to the string NaN
6472 * + positive zero is converted to the string 0
6473 * + negative zero is converted to the string 0
6474 * + positive infinity is converted to the string Infinity
6475 * + negative infinity is converted to the string -Infinity
6476 * + if the number is an integer, the number is represented in
6477 * decimal form as a Number with no decimal point and no leading
6478 * zeros, preceded by a minus sign (-) if the number is negative
6479 * + otherwise, the number is represented in decimal form as a
6480 * Number including a decimal point with at least one digit
6481 * before the decimal point and at least one digit after the
6482 * decimal point, preceded by a minus sign (-) if the number
6483 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006484 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006485 * before the decimal point; beyond the one required digit
6486 * after the decimal point there must be as many, but only as
6487 * many, more digits as are needed to uniquely distinguish the
6488 * number from all other IEEE 754 numeric values.
6489 * - The boolean false value is converted to the string false.
6490 * The boolean true value is converted to the string true.
6491 *
6492 * If the argument is omitted, it defaults to a node-set with the
6493 * context node as its only member.
6494 */
6495void
6496xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6497 xmlXPathObjectPtr cur;
6498
Daniel Veillarda82b1822004-11-08 16:24:57 +00006499 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006500 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006501 valuePush(ctxt,
6502 xmlXPathWrapString(
6503 xmlXPathCastNodeToString(ctxt->context->node)));
6504 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006505 }
6506
6507 CHECK_ARITY(1);
6508 cur = valuePop(ctxt);
6509 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006510 cur = xmlXPathConvertString(cur);
6511 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006512}
6513
6514/**
6515 * xmlXPathStringLengthFunction:
6516 * @ctxt: the XPath Parser context
6517 * @nargs: the number of arguments
6518 *
6519 * Implement the string-length() XPath function
6520 * number string-length(string?)
6521 * The string-length returns the number of characters in the string
6522 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6523 * the context node converted to a string, in other words the value
6524 * of the context node.
6525 */
6526void
6527xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6528 xmlXPathObjectPtr cur;
6529
6530 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006531 if ((ctxt == NULL) || (ctxt->context == NULL))
6532 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006533 if (ctxt->context->node == NULL) {
6534 valuePush(ctxt, xmlXPathNewFloat(0));
6535 } else {
6536 xmlChar *content;
6537
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006538 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006539 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006540 xmlFree(content);
6541 }
6542 return;
6543 }
6544 CHECK_ARITY(1);
6545 CAST_TO_STRING;
6546 CHECK_TYPE(XPATH_STRING);
6547 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006548 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006549 xmlXPathFreeObject(cur);
6550}
6551
6552/**
6553 * xmlXPathConcatFunction:
6554 * @ctxt: the XPath Parser context
6555 * @nargs: the number of arguments
6556 *
6557 * Implement the concat() XPath function
6558 * string concat(string, string, string*)
6559 * The concat function returns the concatenation of its arguments.
6560 */
6561void
6562xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6563 xmlXPathObjectPtr cur, newobj;
6564 xmlChar *tmp;
6565
Daniel Veillarda82b1822004-11-08 16:24:57 +00006566 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006567 if (nargs < 2) {
6568 CHECK_ARITY(2);
6569 }
6570
6571 CAST_TO_STRING;
6572 cur = valuePop(ctxt);
6573 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6574 xmlXPathFreeObject(cur);
6575 return;
6576 }
6577 nargs--;
6578
6579 while (nargs > 0) {
6580 CAST_TO_STRING;
6581 newobj = valuePop(ctxt);
6582 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6583 xmlXPathFreeObject(newobj);
6584 xmlXPathFreeObject(cur);
6585 XP_ERROR(XPATH_INVALID_TYPE);
6586 }
6587 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6588 newobj->stringval = cur->stringval;
6589 cur->stringval = tmp;
6590
6591 xmlXPathFreeObject(newobj);
6592 nargs--;
6593 }
6594 valuePush(ctxt, cur);
6595}
6596
6597/**
6598 * xmlXPathContainsFunction:
6599 * @ctxt: the XPath Parser context
6600 * @nargs: the number of arguments
6601 *
6602 * Implement the contains() XPath function
6603 * boolean contains(string, string)
6604 * The contains function returns true if the first argument string
6605 * contains the second argument string, and otherwise returns false.
6606 */
6607void
6608xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6609 xmlXPathObjectPtr hay, needle;
6610
6611 CHECK_ARITY(2);
6612 CAST_TO_STRING;
6613 CHECK_TYPE(XPATH_STRING);
6614 needle = valuePop(ctxt);
6615 CAST_TO_STRING;
6616 hay = valuePop(ctxt);
6617 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6618 xmlXPathFreeObject(hay);
6619 xmlXPathFreeObject(needle);
6620 XP_ERROR(XPATH_INVALID_TYPE);
6621 }
6622 if (xmlStrstr(hay->stringval, needle->stringval))
6623 valuePush(ctxt, xmlXPathNewBoolean(1));
6624 else
6625 valuePush(ctxt, xmlXPathNewBoolean(0));
6626 xmlXPathFreeObject(hay);
6627 xmlXPathFreeObject(needle);
6628}
6629
6630/**
6631 * xmlXPathStartsWithFunction:
6632 * @ctxt: the XPath Parser context
6633 * @nargs: the number of arguments
6634 *
6635 * Implement the starts-with() XPath function
6636 * boolean starts-with(string, string)
6637 * The starts-with function returns true if the first argument string
6638 * starts with the second argument string, and otherwise returns false.
6639 */
6640void
6641xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6642 xmlXPathObjectPtr hay, needle;
6643 int n;
6644
6645 CHECK_ARITY(2);
6646 CAST_TO_STRING;
6647 CHECK_TYPE(XPATH_STRING);
6648 needle = valuePop(ctxt);
6649 CAST_TO_STRING;
6650 hay = valuePop(ctxt);
6651 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6652 xmlXPathFreeObject(hay);
6653 xmlXPathFreeObject(needle);
6654 XP_ERROR(XPATH_INVALID_TYPE);
6655 }
6656 n = xmlStrlen(needle->stringval);
6657 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6658 valuePush(ctxt, xmlXPathNewBoolean(0));
6659 else
6660 valuePush(ctxt, xmlXPathNewBoolean(1));
6661 xmlXPathFreeObject(hay);
6662 xmlXPathFreeObject(needle);
6663}
6664
6665/**
6666 * xmlXPathSubstringFunction:
6667 * @ctxt: the XPath Parser context
6668 * @nargs: the number of arguments
6669 *
6670 * Implement the substring() XPath function
6671 * string substring(string, number, number?)
6672 * The substring function returns the substring of the first argument
6673 * starting at the position specified in the second argument with
6674 * length specified in the third argument. For example,
6675 * substring("12345",2,3) returns "234". If the third argument is not
6676 * specified, it returns the substring starting at the position specified
6677 * in the second argument and continuing to the end of the string. For
6678 * example, substring("12345",2) returns "2345". More precisely, each
6679 * character in the string (see [3.6 Strings]) is considered to have a
6680 * numeric position: the position of the first character is 1, the position
6681 * of the second character is 2 and so on. The returned substring contains
6682 * those characters for which the position of the character is greater than
6683 * or equal to the second argument and, if the third argument is specified,
6684 * less than the sum of the second and third arguments; the comparisons
6685 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6686 * - substring("12345", 1.5, 2.6) returns "234"
6687 * - substring("12345", 0, 3) returns "12"
6688 * - substring("12345", 0 div 0, 3) returns ""
6689 * - substring("12345", 1, 0 div 0) returns ""
6690 * - substring("12345", -42, 1 div 0) returns "12345"
6691 * - substring("12345", -1 div 0, 1 div 0) returns ""
6692 */
6693void
6694xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6695 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006696 double le=0, in;
6697 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006698 xmlChar *ret;
6699
Owen Taylor3473f882001-02-23 17:55:21 +00006700 if (nargs < 2) {
6701 CHECK_ARITY(2);
6702 }
6703 if (nargs > 3) {
6704 CHECK_ARITY(3);
6705 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006706 /*
6707 * take care of possible last (position) argument
6708 */
Owen Taylor3473f882001-02-23 17:55:21 +00006709 if (nargs == 3) {
6710 CAST_TO_NUMBER;
6711 CHECK_TYPE(XPATH_NUMBER);
6712 len = valuePop(ctxt);
6713 le = len->floatval;
6714 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006715 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006716
Owen Taylor3473f882001-02-23 17:55:21 +00006717 CAST_TO_NUMBER;
6718 CHECK_TYPE(XPATH_NUMBER);
6719 start = valuePop(ctxt);
6720 in = start->floatval;
6721 xmlXPathFreeObject(start);
6722 CAST_TO_STRING;
6723 CHECK_TYPE(XPATH_STRING);
6724 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006725 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006726
Daniel Veillard97ac1312001-05-30 19:14:17 +00006727 /*
6728 * If last pos not present, calculate last position
6729 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006730 if (nargs != 3) {
6731 le = (double)m;
6732 if (in < 1.0)
6733 in = 1.0;
6734 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006735
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006736 /* Need to check for the special cases where either
6737 * the index is NaN, the length is NaN, or both
6738 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006739 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006740 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006741 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006742 * To meet the requirements of the spec, the arguments
6743 * must be converted to integer format before
6744 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006745 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006746 * First we go to integer form, rounding up
6747 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006748 */
6749 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006750 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006751
Daniel Veillard9e412302002-06-10 15:59:44 +00006752 if (xmlXPathIsInf(le) == 1) {
6753 l = m;
6754 if (i < 1)
6755 i = 1;
6756 }
6757 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6758 l = 0;
6759 else {
6760 l = (int) le;
6761 if (((double)l)+0.5 <= le) l++;
6762 }
6763
6764 /* Now we normalize inidices */
6765 i -= 1;
6766 l += i;
6767 if (i < 0)
6768 i = 0;
6769 if (l > m)
6770 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006771
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006772 /* number of chars to copy */
6773 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006774
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006775 ret = xmlUTF8Strsub(str->stringval, i, l);
6776 }
6777 else {
6778 ret = NULL;
6779 }
6780
Owen Taylor3473f882001-02-23 17:55:21 +00006781 if (ret == NULL)
6782 valuePush(ctxt, xmlXPathNewCString(""));
6783 else {
6784 valuePush(ctxt, xmlXPathNewString(ret));
6785 xmlFree(ret);
6786 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006787
Owen Taylor3473f882001-02-23 17:55:21 +00006788 xmlXPathFreeObject(str);
6789}
6790
6791/**
6792 * xmlXPathSubstringBeforeFunction:
6793 * @ctxt: the XPath Parser context
6794 * @nargs: the number of arguments
6795 *
6796 * Implement the substring-before() XPath function
6797 * string substring-before(string, string)
6798 * The substring-before function returns the substring of the first
6799 * argument string that precedes the first occurrence of the second
6800 * argument string in the first argument string, or the empty string
6801 * if the first argument string does not contain the second argument
6802 * string. For example, substring-before("1999/04/01","/") returns 1999.
6803 */
6804void
6805xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6806 xmlXPathObjectPtr str;
6807 xmlXPathObjectPtr find;
6808 xmlBufferPtr target;
6809 const xmlChar *point;
6810 int offset;
6811
6812 CHECK_ARITY(2);
6813 CAST_TO_STRING;
6814 find = valuePop(ctxt);
6815 CAST_TO_STRING;
6816 str = valuePop(ctxt);
6817
6818 target = xmlBufferCreate();
6819 if (target) {
6820 point = xmlStrstr(str->stringval, find->stringval);
6821 if (point) {
6822 offset = (int)(point - str->stringval);
6823 xmlBufferAdd(target, str->stringval, offset);
6824 }
6825 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6826 xmlBufferFree(target);
6827 }
6828
6829 xmlXPathFreeObject(str);
6830 xmlXPathFreeObject(find);
6831}
6832
6833/**
6834 * xmlXPathSubstringAfterFunction:
6835 * @ctxt: the XPath Parser context
6836 * @nargs: the number of arguments
6837 *
6838 * Implement the substring-after() XPath function
6839 * string substring-after(string, string)
6840 * The substring-after function returns the substring of the first
6841 * argument string that follows the first occurrence of the second
6842 * argument string in the first argument string, or the empty stringi
6843 * if the first argument string does not contain the second argument
6844 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6845 * and substring-after("1999/04/01","19") returns 99/04/01.
6846 */
6847void
6848xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6849 xmlXPathObjectPtr str;
6850 xmlXPathObjectPtr find;
6851 xmlBufferPtr target;
6852 const xmlChar *point;
6853 int offset;
6854
6855 CHECK_ARITY(2);
6856 CAST_TO_STRING;
6857 find = valuePop(ctxt);
6858 CAST_TO_STRING;
6859 str = valuePop(ctxt);
6860
6861 target = xmlBufferCreate();
6862 if (target) {
6863 point = xmlStrstr(str->stringval, find->stringval);
6864 if (point) {
6865 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6866 xmlBufferAdd(target, &str->stringval[offset],
6867 xmlStrlen(str->stringval) - offset);
6868 }
6869 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6870 xmlBufferFree(target);
6871 }
6872
6873 xmlXPathFreeObject(str);
6874 xmlXPathFreeObject(find);
6875}
6876
6877/**
6878 * xmlXPathNormalizeFunction:
6879 * @ctxt: the XPath Parser context
6880 * @nargs: the number of arguments
6881 *
6882 * Implement the normalize-space() XPath function
6883 * string normalize-space(string?)
6884 * The normalize-space function returns the argument string with white
6885 * space normalized by stripping leading and trailing whitespace
6886 * and replacing sequences of whitespace characters by a single
6887 * space. Whitespace characters are the same allowed by the S production
6888 * in XML. If the argument is omitted, it defaults to the context
6889 * node converted to a string, in other words the value of the context node.
6890 */
6891void
6892xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6893 xmlXPathObjectPtr obj = NULL;
6894 xmlChar *source = NULL;
6895 xmlBufferPtr target;
6896 xmlChar blank;
6897
Daniel Veillarda82b1822004-11-08 16:24:57 +00006898 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006899 if (nargs == 0) {
6900 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006901 valuePush(ctxt,
6902 xmlXPathWrapString(
6903 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006904 nargs = 1;
6905 }
6906
6907 CHECK_ARITY(1);
6908 CAST_TO_STRING;
6909 CHECK_TYPE(XPATH_STRING);
6910 obj = valuePop(ctxt);
6911 source = obj->stringval;
6912
6913 target = xmlBufferCreate();
6914 if (target && source) {
6915
6916 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006917 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006918 source++;
6919
6920 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6921 blank = 0;
6922 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006923 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006924 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006925 } else {
6926 if (blank) {
6927 xmlBufferAdd(target, &blank, 1);
6928 blank = 0;
6929 }
6930 xmlBufferAdd(target, source, 1);
6931 }
6932 source++;
6933 }
6934
6935 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6936 xmlBufferFree(target);
6937 }
6938 xmlXPathFreeObject(obj);
6939}
6940
6941/**
6942 * xmlXPathTranslateFunction:
6943 * @ctxt: the XPath Parser context
6944 * @nargs: the number of arguments
6945 *
6946 * Implement the translate() XPath function
6947 * string translate(string, string, string)
6948 * The translate function returns the first argument string with
6949 * occurrences of characters in the second argument string replaced
6950 * by the character at the corresponding position in the third argument
6951 * string. For example, translate("bar","abc","ABC") returns the string
6952 * BAr. If there is a character in the second argument string with no
6953 * character at a corresponding position in the third argument string
6954 * (because the second argument string is longer than the third argument
6955 * string), then occurrences of that character in the first argument
6956 * string are removed. For example, translate("--aaa--","abc-","ABC")
6957 * returns "AAA". If a character occurs more than once in second
6958 * argument string, then the first occurrence determines the replacement
6959 * character. If the third argument string is longer than the second
6960 * argument string, then excess characters are ignored.
6961 */
6962void
6963xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006964 xmlXPathObjectPtr str;
6965 xmlXPathObjectPtr from;
6966 xmlXPathObjectPtr to;
6967 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006968 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006969 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00006970 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006971 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006972
Daniel Veillarde043ee12001-04-16 14:08:07 +00006973 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006974
Daniel Veillarde043ee12001-04-16 14:08:07 +00006975 CAST_TO_STRING;
6976 to = valuePop(ctxt);
6977 CAST_TO_STRING;
6978 from = valuePop(ctxt);
6979 CAST_TO_STRING;
6980 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006981
Daniel Veillarde043ee12001-04-16 14:08:07 +00006982 target = xmlBufferCreate();
6983 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006984 max = xmlUTF8Strlen(to->stringval);
6985 for (cptr = str->stringval; (ch=*cptr); ) {
6986 offset = xmlUTF8Strloc(from->stringval, cptr);
6987 if (offset >= 0) {
6988 if (offset < max) {
6989 point = xmlUTF8Strpos(to->stringval, offset);
6990 if (point)
6991 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6992 }
6993 } else
6994 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6995
6996 /* Step to next character in input */
6997 cptr++;
6998 if ( ch & 0x80 ) {
6999 /* if not simple ascii, verify proper format */
7000 if ( (ch & 0xc0) != 0xc0 ) {
7001 xmlGenericError(xmlGenericErrorContext,
7002 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
7003 break;
7004 }
7005 /* then skip over remaining bytes for this char */
7006 while ( (ch <<= 1) & 0x80 )
7007 if ( (*cptr++ & 0xc0) != 0x80 ) {
7008 xmlGenericError(xmlGenericErrorContext,
7009 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
7010 break;
7011 }
7012 if (ch & 0x80) /* must have had error encountered */
7013 break;
7014 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00007015 }
Owen Taylor3473f882001-02-23 17:55:21 +00007016 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00007017 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
7018 xmlBufferFree(target);
7019 xmlXPathFreeObject(str);
7020 xmlXPathFreeObject(from);
7021 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00007022}
7023
7024/**
7025 * xmlXPathBooleanFunction:
7026 * @ctxt: the XPath Parser context
7027 * @nargs: the number of arguments
7028 *
7029 * Implement the boolean() XPath function
7030 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00007031 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00007032 * - a number is true if and only if it is neither positive or
7033 * negative zero nor NaN
7034 * - a node-set is true if and only if it is non-empty
7035 * - a string is true if and only if its length is non-zero
7036 */
7037void
7038xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7039 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00007040
7041 CHECK_ARITY(1);
7042 cur = valuePop(ctxt);
7043 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007044 cur = xmlXPathConvertBoolean(cur);
7045 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007046}
7047
7048/**
7049 * xmlXPathNotFunction:
7050 * @ctxt: the XPath Parser context
7051 * @nargs: the number of arguments
7052 *
7053 * Implement the not() XPath function
7054 * boolean not(boolean)
7055 * The not function returns true if its argument is false,
7056 * and false otherwise.
7057 */
7058void
7059xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7060 CHECK_ARITY(1);
7061 CAST_TO_BOOLEAN;
7062 CHECK_TYPE(XPATH_BOOLEAN);
7063 ctxt->value->boolval = ! ctxt->value->boolval;
7064}
7065
7066/**
7067 * xmlXPathTrueFunction:
7068 * @ctxt: the XPath Parser context
7069 * @nargs: the number of arguments
7070 *
7071 * Implement the true() XPath function
7072 * boolean true()
7073 */
7074void
7075xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7076 CHECK_ARITY(0);
7077 valuePush(ctxt, xmlXPathNewBoolean(1));
7078}
7079
7080/**
7081 * xmlXPathFalseFunction:
7082 * @ctxt: the XPath Parser context
7083 * @nargs: the number of arguments
7084 *
7085 * Implement the false() XPath function
7086 * boolean false()
7087 */
7088void
7089xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7090 CHECK_ARITY(0);
7091 valuePush(ctxt, xmlXPathNewBoolean(0));
7092}
7093
7094/**
7095 * xmlXPathLangFunction:
7096 * @ctxt: the XPath Parser context
7097 * @nargs: the number of arguments
7098 *
7099 * Implement the lang() XPath function
7100 * boolean lang(string)
7101 * The lang function returns true or false depending on whether the
7102 * language of the context node as specified by xml:lang attributes
7103 * is the same as or is a sublanguage of the language specified by
7104 * the argument string. The language of the context node is determined
7105 * by the value of the xml:lang attribute on the context node, or, if
7106 * the context node has no xml:lang attribute, by the value of the
7107 * xml:lang attribute on the nearest ancestor of the context node that
7108 * has an xml:lang attribute. If there is no such attribute, then lang
7109 * returns false. If there is such an attribute, then lang returns
7110 * true if the attribute value is equal to the argument ignoring case,
7111 * or if there is some suffix starting with - such that the attribute
7112 * value is equal to the argument ignoring that suffix of the attribute
7113 * value and ignoring case.
7114 */
7115void
7116xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007117 xmlXPathObjectPtr val = NULL;
7118 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00007119 const xmlChar *lang;
7120 int ret = 0;
7121 int i;
7122
7123 CHECK_ARITY(1);
7124 CAST_TO_STRING;
7125 CHECK_TYPE(XPATH_STRING);
7126 val = valuePop(ctxt);
7127 lang = val->stringval;
7128 theLang = xmlNodeGetLang(ctxt->context->node);
7129 if ((theLang != NULL) && (lang != NULL)) {
7130 for (i = 0;lang[i] != 0;i++)
7131 if (toupper(lang[i]) != toupper(theLang[i]))
7132 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007133 if ((theLang[i] == 0) || (theLang[i] == '-'))
7134 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007135 }
7136not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007137 if (theLang != NULL)
7138 xmlFree((void *)theLang);
Owen Taylor3473f882001-02-23 17:55:21 +00007139 xmlXPathFreeObject(val);
7140 valuePush(ctxt, xmlXPathNewBoolean(ret));
7141}
7142
7143/**
7144 * xmlXPathNumberFunction:
7145 * @ctxt: the XPath Parser context
7146 * @nargs: the number of arguments
7147 *
7148 * Implement the number() XPath function
7149 * number number(object?)
7150 */
7151void
7152xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7153 xmlXPathObjectPtr cur;
7154 double res;
7155
Daniel Veillarda82b1822004-11-08 16:24:57 +00007156 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007157 if (nargs == 0) {
7158 if (ctxt->context->node == NULL) {
7159 valuePush(ctxt, xmlXPathNewFloat(0.0));
7160 } else {
7161 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7162
7163 res = xmlXPathStringEvalNumber(content);
7164 valuePush(ctxt, xmlXPathNewFloat(res));
7165 xmlFree(content);
7166 }
7167 return;
7168 }
7169
7170 CHECK_ARITY(1);
7171 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007172 cur = xmlXPathConvertNumber(cur);
7173 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007174}
7175
7176/**
7177 * xmlXPathSumFunction:
7178 * @ctxt: the XPath Parser context
7179 * @nargs: the number of arguments
7180 *
7181 * Implement the sum() XPath function
7182 * number sum(node-set)
7183 * The sum function returns the sum of the values of the nodes in
7184 * the argument node-set.
7185 */
7186void
7187xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7188 xmlXPathObjectPtr cur;
7189 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007190 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007191
7192 CHECK_ARITY(1);
7193 if ((ctxt->value == NULL) ||
7194 ((ctxt->value->type != XPATH_NODESET) &&
7195 (ctxt->value->type != XPATH_XSLT_TREE)))
7196 XP_ERROR(XPATH_INVALID_TYPE);
7197 cur = valuePop(ctxt);
7198
William M. Brack08171912003-12-29 02:52:11 +00007199 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007200 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7201 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007202 }
7203 }
William M. Brack08171912003-12-29 02:52:11 +00007204 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007205 xmlXPathFreeObject(cur);
7206}
7207
William M. Brack3d426662005-04-19 14:40:28 +00007208/*
7209 * To assure working code on multiple platforms, we want to only depend
7210 * upon the characteristic truncation of converting a floating point value
7211 * to an integer. Unfortunately, because of the different storage sizes
7212 * of our internal floating point value (double) and integer (int), we
7213 * can't directly convert (see bug 301162). This macro is a messy
7214 * 'workaround'
7215 */
7216#define XTRUNC(f, v) \
7217 f = fmod((v), INT_MAX); \
7218 f = (v) - (f) + (double)((int)(f));
7219
Owen Taylor3473f882001-02-23 17:55:21 +00007220/**
7221 * xmlXPathFloorFunction:
7222 * @ctxt: the XPath Parser context
7223 * @nargs: the number of arguments
7224 *
7225 * Implement the floor() XPath function
7226 * number floor(number)
7227 * The floor function returns the largest (closest to positive infinity)
7228 * number that is not greater than the argument and that is an integer.
7229 */
7230void
7231xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007232 double f;
7233
Owen Taylor3473f882001-02-23 17:55:21 +00007234 CHECK_ARITY(1);
7235 CAST_TO_NUMBER;
7236 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007237
William M. Brack3d426662005-04-19 14:40:28 +00007238 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007239 if (f != ctxt->value->floatval) {
7240 if (ctxt->value->floatval > 0)
7241 ctxt->value->floatval = f;
7242 else
7243 ctxt->value->floatval = f - 1;
7244 }
Owen Taylor3473f882001-02-23 17:55:21 +00007245}
7246
7247/**
7248 * xmlXPathCeilingFunction:
7249 * @ctxt: the XPath Parser context
7250 * @nargs: the number of arguments
7251 *
7252 * Implement the ceiling() XPath function
7253 * number ceiling(number)
7254 * The ceiling function returns the smallest (closest to negative infinity)
7255 * number that is not less than the argument and that is an integer.
7256 */
7257void
7258xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7259 double f;
7260
7261 CHECK_ARITY(1);
7262 CAST_TO_NUMBER;
7263 CHECK_TYPE(XPATH_NUMBER);
7264
7265#if 0
7266 ctxt->value->floatval = ceil(ctxt->value->floatval);
7267#else
William M. Brack3d426662005-04-19 14:40:28 +00007268 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007269 if (f != ctxt->value->floatval) {
7270 if (ctxt->value->floatval > 0)
7271 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007272 else {
7273 if (ctxt->value->floatval < 0 && f == 0)
7274 ctxt->value->floatval = xmlXPathNZERO;
7275 else
7276 ctxt->value->floatval = f;
7277 }
7278
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007279 }
Owen Taylor3473f882001-02-23 17:55:21 +00007280#endif
7281}
7282
7283/**
7284 * xmlXPathRoundFunction:
7285 * @ctxt: the XPath Parser context
7286 * @nargs: the number of arguments
7287 *
7288 * Implement the round() XPath function
7289 * number round(number)
7290 * The round function returns the number that is closest to the
7291 * argument and that is an integer. If there are two such numbers,
7292 * then the one that is even is returned.
7293 */
7294void
7295xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7296 double f;
7297
7298 CHECK_ARITY(1);
7299 CAST_TO_NUMBER;
7300 CHECK_TYPE(XPATH_NUMBER);
7301
Daniel Veillardcda96922001-08-21 10:56:31 +00007302 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7303 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7304 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007305 (ctxt->value->floatval == 0.0))
7306 return;
7307
William M. Brack3d426662005-04-19 14:40:28 +00007308 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007309 if (ctxt->value->floatval < 0) {
7310 if (ctxt->value->floatval < f - 0.5)
7311 ctxt->value->floatval = f - 1;
7312 else
7313 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007314 if (ctxt->value->floatval == 0)
7315 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007316 } else {
7317 if (ctxt->value->floatval < f + 0.5)
7318 ctxt->value->floatval = f;
7319 else
7320 ctxt->value->floatval = f + 1;
7321 }
Owen Taylor3473f882001-02-23 17:55:21 +00007322}
7323
7324/************************************************************************
7325 * *
7326 * The Parser *
7327 * *
7328 ************************************************************************/
7329
7330/*
William M. Brack08171912003-12-29 02:52:11 +00007331 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007332 * implementation.
7333 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007334static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007335static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007336static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007337static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007338static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7339 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007340
7341/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007342 * xmlXPathCurrentChar:
7343 * @ctxt: the XPath parser context
7344 * @cur: pointer to the beginning of the char
7345 * @len: pointer to the length of the char read
7346 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007347 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007348 * bytes in the input buffer.
7349 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007350 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007351 */
7352
7353static int
7354xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7355 unsigned char c;
7356 unsigned int val;
7357 const xmlChar *cur;
7358
7359 if (ctxt == NULL)
7360 return(0);
7361 cur = ctxt->cur;
7362
7363 /*
7364 * We are supposed to handle UTF8, check it's valid
7365 * From rfc2044: encoding of the Unicode values on UTF-8:
7366 *
7367 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7368 * 0000 0000-0000 007F 0xxxxxxx
7369 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7370 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7371 *
7372 * Check for the 0x110000 limit too
7373 */
7374 c = *cur;
7375 if (c & 0x80) {
7376 if ((cur[1] & 0xc0) != 0x80)
7377 goto encoding_error;
7378 if ((c & 0xe0) == 0xe0) {
7379
7380 if ((cur[2] & 0xc0) != 0x80)
7381 goto encoding_error;
7382 if ((c & 0xf0) == 0xf0) {
7383 if (((c & 0xf8) != 0xf0) ||
7384 ((cur[3] & 0xc0) != 0x80))
7385 goto encoding_error;
7386 /* 4-byte code */
7387 *len = 4;
7388 val = (cur[0] & 0x7) << 18;
7389 val |= (cur[1] & 0x3f) << 12;
7390 val |= (cur[2] & 0x3f) << 6;
7391 val |= cur[3] & 0x3f;
7392 } else {
7393 /* 3-byte code */
7394 *len = 3;
7395 val = (cur[0] & 0xf) << 12;
7396 val |= (cur[1] & 0x3f) << 6;
7397 val |= cur[2] & 0x3f;
7398 }
7399 } else {
7400 /* 2-byte code */
7401 *len = 2;
7402 val = (cur[0] & 0x1f) << 6;
7403 val |= cur[1] & 0x3f;
7404 }
7405 if (!IS_CHAR(val)) {
7406 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7407 }
7408 return(val);
7409 } else {
7410 /* 1-byte code */
7411 *len = 1;
7412 return((int) *cur);
7413 }
7414encoding_error:
7415 /*
William M. Brack08171912003-12-29 02:52:11 +00007416 * If we detect an UTF8 error that probably means that the
7417 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007418 * declaration header. Report the error and switch the encoding
7419 * to ISO-Latin-1 (if you don't like this policy, just declare the
7420 * encoding !)
7421 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007422 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007423 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007424}
7425
7426/**
Owen Taylor3473f882001-02-23 17:55:21 +00007427 * xmlXPathParseNCName:
7428 * @ctxt: the XPath Parser context
7429 *
7430 * parse an XML namespace non qualified name.
7431 *
7432 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7433 *
7434 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7435 * CombiningChar | Extender
7436 *
7437 * Returns the namespace name or NULL
7438 */
7439
7440xmlChar *
7441xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007442 const xmlChar *in;
7443 xmlChar *ret;
7444 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007445
Daniel Veillarda82b1822004-11-08 16:24:57 +00007446 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00007447 /*
7448 * Accelerator for simple ASCII names
7449 */
7450 in = ctxt->cur;
7451 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7452 ((*in >= 0x41) && (*in <= 0x5A)) ||
7453 (*in == '_')) {
7454 in++;
7455 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7456 ((*in >= 0x41) && (*in <= 0x5A)) ||
7457 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007458 (*in == '_') || (*in == '.') ||
7459 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007460 in++;
7461 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7462 (*in == '[') || (*in == ']') || (*in == ':') ||
7463 (*in == '@') || (*in == '*')) {
7464 count = in - ctxt->cur;
7465 if (count == 0)
7466 return(NULL);
7467 ret = xmlStrndup(ctxt->cur, count);
7468 ctxt->cur = in;
7469 return(ret);
7470 }
7471 }
7472 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007473}
7474
Daniel Veillard2156a562001-04-28 12:24:34 +00007475
Owen Taylor3473f882001-02-23 17:55:21 +00007476/**
7477 * xmlXPathParseQName:
7478 * @ctxt: the XPath Parser context
7479 * @prefix: a xmlChar **
7480 *
7481 * parse an XML qualified name
7482 *
7483 * [NS 5] QName ::= (Prefix ':')? LocalPart
7484 *
7485 * [NS 6] Prefix ::= NCName
7486 *
7487 * [NS 7] LocalPart ::= NCName
7488 *
7489 * Returns the function returns the local part, and prefix is updated
7490 * to get the Prefix if any.
7491 */
7492
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007493static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007494xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7495 xmlChar *ret = NULL;
7496
7497 *prefix = NULL;
7498 ret = xmlXPathParseNCName(ctxt);
7499 if (CUR == ':') {
7500 *prefix = ret;
7501 NEXT;
7502 ret = xmlXPathParseNCName(ctxt);
7503 }
7504 return(ret);
7505}
7506
7507/**
7508 * xmlXPathParseName:
7509 * @ctxt: the XPath Parser context
7510 *
7511 * parse an XML name
7512 *
7513 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7514 * CombiningChar | Extender
7515 *
7516 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7517 *
7518 * Returns the namespace name or NULL
7519 */
7520
7521xmlChar *
7522xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007523 const xmlChar *in;
7524 xmlChar *ret;
7525 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007526
Daniel Veillarda82b1822004-11-08 16:24:57 +00007527 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007528 /*
7529 * Accelerator for simple ASCII names
7530 */
7531 in = ctxt->cur;
7532 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7533 ((*in >= 0x41) && (*in <= 0x5A)) ||
7534 (*in == '_') || (*in == ':')) {
7535 in++;
7536 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7537 ((*in >= 0x41) && (*in <= 0x5A)) ||
7538 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007539 (*in == '_') || (*in == '-') ||
7540 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007541 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007542 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007543 count = in - ctxt->cur;
7544 ret = xmlStrndup(ctxt->cur, count);
7545 ctxt->cur = in;
7546 return(ret);
7547 }
7548 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007549 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007550}
7551
Daniel Veillard61d80a22001-04-27 17:13:01 +00007552static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007553xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007554 xmlChar buf[XML_MAX_NAMELEN + 5];
7555 int len = 0, l;
7556 int c;
7557
7558 /*
7559 * Handler for more complex cases
7560 */
7561 c = CUR_CHAR(l);
7562 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007563 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7564 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007565 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007566 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007567 return(NULL);
7568 }
7569
7570 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7571 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7572 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007573 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007574 (IS_COMBINING(c)) ||
7575 (IS_EXTENDER(c)))) {
7576 COPY_BUF(l,buf,len,c);
7577 NEXTL(l);
7578 c = CUR_CHAR(l);
7579 if (len >= XML_MAX_NAMELEN) {
7580 /*
7581 * Okay someone managed to make a huge name, so he's ready to pay
7582 * for the processing speed.
7583 */
7584 xmlChar *buffer;
7585 int max = len * 2;
7586
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007587 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007588 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00007589 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007590 }
7591 memcpy(buffer, buf, len);
7592 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7593 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007594 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007595 (IS_COMBINING(c)) ||
7596 (IS_EXTENDER(c))) {
7597 if (len + 10 > max) {
7598 max *= 2;
7599 buffer = (xmlChar *) xmlRealloc(buffer,
7600 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007601 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00007602 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007603 }
7604 }
7605 COPY_BUF(l,buffer,len,c);
7606 NEXTL(l);
7607 c = CUR_CHAR(l);
7608 }
7609 buffer[len] = 0;
7610 return(buffer);
7611 }
7612 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007613 if (len == 0)
7614 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007615 return(xmlStrndup(buf, len));
7616}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007617
7618#define MAX_FRAC 20
7619
William M. Brack372a4452004-02-17 13:09:23 +00007620/*
7621 * These are used as divisors for the fractional part of a number.
7622 * Since the table includes 1.0 (representing '0' fractional digits),
7623 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
7624 */
7625static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007626 1.0, 10.0, 100.0, 1000.0, 10000.0,
7627 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7628 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7629 100000000000000.0,
7630 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00007631 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00007632};
7633
Owen Taylor3473f882001-02-23 17:55:21 +00007634/**
7635 * xmlXPathStringEvalNumber:
7636 * @str: A string to scan
7637 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007638 * [30a] Float ::= Number ('e' Digits?)?
7639 *
Owen Taylor3473f882001-02-23 17:55:21 +00007640 * [30] Number ::= Digits ('.' Digits?)?
7641 * | '.' Digits
7642 * [31] Digits ::= [0-9]+
7643 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007644 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007645 * In complement of the Number expression, this function also handles
7646 * negative values : '-' Number.
7647 *
7648 * Returns the double value.
7649 */
7650double
7651xmlXPathStringEvalNumber(const xmlChar *str) {
7652 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007653 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007654 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007655 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007656 int exponent = 0;
7657 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007658#ifdef __GNUC__
7659 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007660 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007661#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007662 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007663 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007664 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7665 return(xmlXPathNAN);
7666 }
7667 if (*cur == '-') {
7668 isneg = 1;
7669 cur++;
7670 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007671
7672#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007673 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007674 * tmp/temp is a workaround against a gcc compiler bug
7675 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007676 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007677 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007678 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007679 ret = ret * 10;
7680 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007681 ok = 1;
7682 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007683 temp = (double) tmp;
7684 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007685 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007686#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007687 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007688 while ((*cur >= '0') && (*cur <= '9')) {
7689 ret = ret * 10 + (*cur - '0');
7690 ok = 1;
7691 cur++;
7692 }
7693#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007694
Owen Taylor3473f882001-02-23 17:55:21 +00007695 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007696 int v, frac = 0;
7697 double fraction = 0;
7698
Owen Taylor3473f882001-02-23 17:55:21 +00007699 cur++;
7700 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7701 return(xmlXPathNAN);
7702 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007703 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7704 v = (*cur - '0');
7705 fraction = fraction * 10 + v;
7706 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007707 cur++;
7708 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007709 fraction /= my_pow10[frac];
7710 ret = ret + fraction;
7711 while ((*cur >= '0') && (*cur <= '9'))
7712 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007713 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007714 if ((*cur == 'e') || (*cur == 'E')) {
7715 cur++;
7716 if (*cur == '-') {
7717 is_exponent_negative = 1;
7718 cur++;
William M. Brack99127052004-05-24 02:52:28 +00007719 } else if (*cur == '+') {
7720 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007721 }
7722 while ((*cur >= '0') && (*cur <= '9')) {
7723 exponent = exponent * 10 + (*cur - '0');
7724 cur++;
7725 }
7726 }
William M. Brack76e95df2003-10-18 16:20:14 +00007727 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007728 if (*cur != 0) return(xmlXPathNAN);
7729 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007730 if (is_exponent_negative) exponent = -exponent;
7731 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007732 return(ret);
7733}
7734
7735/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007736 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007737 * @ctxt: the XPath Parser context
7738 *
7739 * [30] Number ::= Digits ('.' Digits?)?
7740 * | '.' Digits
7741 * [31] Digits ::= [0-9]+
7742 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007743 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007744 *
7745 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007746static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007747xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7748{
Owen Taylor3473f882001-02-23 17:55:21 +00007749 double ret = 0.0;
7750 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007751 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007752 int exponent = 0;
7753 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007754#ifdef __GNUC__
7755 unsigned long tmp = 0;
7756 double temp;
7757#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007758
7759 CHECK_ERROR;
7760 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7761 XP_ERROR(XPATH_NUMBER_ERROR);
7762 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007763#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007764 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007765 * tmp/temp is a workaround against a gcc compiler bug
7766 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007767 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007768 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007769 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007770 ret = ret * 10;
7771 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007772 ok = 1;
7773 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007774 temp = (double) tmp;
7775 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007776 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007777#else
7778 ret = 0;
7779 while ((CUR >= '0') && (CUR <= '9')) {
7780 ret = ret * 10 + (CUR - '0');
7781 ok = 1;
7782 NEXT;
7783 }
7784#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007785 if (CUR == '.') {
7786 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007787 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7788 XP_ERROR(XPATH_NUMBER_ERROR);
7789 }
7790 while ((CUR >= '0') && (CUR <= '9')) {
7791 mult /= 10;
7792 ret = ret + (CUR - '0') * mult;
7793 NEXT;
7794 }
Owen Taylor3473f882001-02-23 17:55:21 +00007795 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007796 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007797 NEXT;
7798 if (CUR == '-') {
7799 is_exponent_negative = 1;
7800 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00007801 } else if (CUR == '+') {
7802 NEXT;
7803 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007804 while ((CUR >= '0') && (CUR <= '9')) {
7805 exponent = exponent * 10 + (CUR - '0');
7806 NEXT;
7807 }
7808 if (is_exponent_negative)
7809 exponent = -exponent;
7810 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007811 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007812 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007813 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007814}
7815
7816/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007817 * xmlXPathParseLiteral:
7818 * @ctxt: the XPath Parser context
7819 *
7820 * Parse a Literal
7821 *
7822 * [29] Literal ::= '"' [^"]* '"'
7823 * | "'" [^']* "'"
7824 *
7825 * Returns the value found or NULL in case of error
7826 */
7827static xmlChar *
7828xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7829 const xmlChar *q;
7830 xmlChar *ret = NULL;
7831
7832 if (CUR == '"') {
7833 NEXT;
7834 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007835 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007836 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007837 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +00007838 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007839 } else {
7840 ret = xmlStrndup(q, CUR_PTR - q);
7841 NEXT;
7842 }
7843 } else if (CUR == '\'') {
7844 NEXT;
7845 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007846 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007847 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007848 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +00007849 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007850 } else {
7851 ret = xmlStrndup(q, CUR_PTR - q);
7852 NEXT;
7853 }
7854 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +00007855 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007856 }
7857 return(ret);
7858}
7859
7860/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007861 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007862 * @ctxt: the XPath Parser context
7863 *
7864 * Parse a Literal and push it on the stack.
7865 *
7866 * [29] Literal ::= '"' [^"]* '"'
7867 * | "'" [^']* "'"
7868 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007869 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007870 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007871static void
7872xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007873 const xmlChar *q;
7874 xmlChar *ret = NULL;
7875
7876 if (CUR == '"') {
7877 NEXT;
7878 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007879 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007880 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007881 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007882 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7883 } else {
7884 ret = xmlStrndup(q, CUR_PTR - q);
7885 NEXT;
7886 }
7887 } else if (CUR == '\'') {
7888 NEXT;
7889 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007890 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007891 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007892 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007893 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7894 } else {
7895 ret = xmlStrndup(q, CUR_PTR - q);
7896 NEXT;
7897 }
7898 } else {
7899 XP_ERROR(XPATH_START_LITERAL_ERROR);
7900 }
7901 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007902 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7903 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007904 xmlFree(ret);
7905}
7906
7907/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007908 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007909 * @ctxt: the XPath Parser context
7910 *
7911 * Parse a VariableReference, evaluate it and push it on the stack.
7912 *
7913 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00007914 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00007915 * of any of the types that are possible for the value of an expression,
7916 * and may also be of additional types not specified here.
7917 *
7918 * Early evaluation is possible since:
7919 * The variable bindings [...] used to evaluate a subexpression are
7920 * always the same as those used to evaluate the containing expression.
7921 *
7922 * [36] VariableReference ::= '$' QName
7923 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007924static void
7925xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007926 xmlChar *name;
7927 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007928
7929 SKIP_BLANKS;
7930 if (CUR != '$') {
7931 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7932 }
7933 NEXT;
7934 name = xmlXPathParseQName(ctxt, &prefix);
7935 if (name == NULL) {
7936 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7937 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007938 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007939 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7940 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007941 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +00007942 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
7943 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
7944 }
Owen Taylor3473f882001-02-23 17:55:21 +00007945}
7946
7947/**
7948 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007949 * @name: a name string
7950 *
7951 * Is the name given a NodeType one.
7952 *
7953 * [38] NodeType ::= 'comment'
7954 * | 'text'
7955 * | 'processing-instruction'
7956 * | 'node'
7957 *
7958 * Returns 1 if true 0 otherwise
7959 */
7960int
7961xmlXPathIsNodeType(const xmlChar *name) {
7962 if (name == NULL)
7963 return(0);
7964
Daniel Veillard1971ee22002-01-31 20:29:19 +00007965 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007966 return(1);
7967 if (xmlStrEqual(name, BAD_CAST "text"))
7968 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007969 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007970 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007971 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007972 return(1);
7973 return(0);
7974}
7975
7976/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007977 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007978 * @ctxt: the XPath Parser context
7979 *
7980 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7981 * [17] Argument ::= Expr
7982 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007983 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007984 * pushed on the stack
7985 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007986static void
7987xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007988 xmlChar *name;
7989 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007990 int nbargs = 0;
7991
7992 name = xmlXPathParseQName(ctxt, &prefix);
7993 if (name == NULL) {
7994 XP_ERROR(XPATH_EXPR_ERROR);
7995 }
7996 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007997#ifdef DEBUG_EXPR
7998 if (prefix == NULL)
7999 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
8000 name);
8001 else
8002 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
8003 prefix, name);
8004#endif
8005
Owen Taylor3473f882001-02-23 17:55:21 +00008006 if (CUR != '(') {
8007 XP_ERROR(XPATH_EXPR_ERROR);
8008 }
8009 NEXT;
8010 SKIP_BLANKS;
8011
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008012 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00008013 if (CUR != ')') {
8014 while (CUR != 0) {
8015 int op1 = ctxt->comp->last;
8016 ctxt->comp->last = -1;
8017 xmlXPathCompileExpr(ctxt);
8018 CHECK_ERROR;
8019 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
8020 nbargs++;
8021 if (CUR == ')') break;
8022 if (CUR != ',') {
8023 XP_ERROR(XPATH_EXPR_ERROR);
8024 }
8025 NEXT;
8026 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00008027 }
Owen Taylor3473f882001-02-23 17:55:21 +00008028 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008029 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
8030 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00008031 NEXT;
8032 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00008033}
8034
8035/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008036 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008037 * @ctxt: the XPath Parser context
8038 *
8039 * [15] PrimaryExpr ::= VariableReference
8040 * | '(' Expr ')'
8041 * | Literal
8042 * | Number
8043 * | FunctionCall
8044 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008045 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008046 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008047static void
8048xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008049 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008050 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008051 else if (CUR == '(') {
8052 NEXT;
8053 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008054 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00008055 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00008056 if (CUR != ')') {
8057 XP_ERROR(XPATH_EXPR_ERROR);
8058 }
8059 NEXT;
8060 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008061 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008062 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008063 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008064 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008065 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008066 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008067 }
8068 SKIP_BLANKS;
8069}
8070
8071/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008072 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008073 * @ctxt: the XPath Parser context
8074 *
8075 * [20] FilterExpr ::= PrimaryExpr
8076 * | FilterExpr Predicate
8077 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008078 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008079 * Square brackets are used to filter expressions in the same way that
8080 * they are used in location paths. It is an error if the expression to
8081 * be filtered does not evaluate to a node-set. The context node list
8082 * used for evaluating the expression in square brackets is the node-set
8083 * to be filtered listed in document order.
8084 */
8085
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008086static void
8087xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8088 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008089 CHECK_ERROR;
8090 SKIP_BLANKS;
8091
8092 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008093 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00008094 SKIP_BLANKS;
8095 }
8096
8097
8098}
8099
8100/**
8101 * xmlXPathScanName:
8102 * @ctxt: the XPath Parser context
8103 *
8104 * Trickery: parse an XML name but without consuming the input flow
8105 * Needed to avoid insanity in the parser state.
8106 *
8107 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8108 * CombiningChar | Extender
8109 *
8110 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8111 *
8112 * [6] Names ::= Name (S Name)*
8113 *
8114 * Returns the Name parsed or NULL
8115 */
8116
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008117static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00008118xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +00008119 int len = 0, l;
8120 int c;
Daniel Veillard03226812004-11-01 14:55:21 +00008121 const xmlChar *cur;
8122 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00008123
Daniel Veillard03226812004-11-01 14:55:21 +00008124 cur = ctxt->cur;
8125
8126 c = CUR_CHAR(l);
8127 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8128 (!IS_LETTER(c) && (c != '_') &&
8129 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008130 return(NULL);
8131 }
8132
Daniel Veillard03226812004-11-01 14:55:21 +00008133 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8134 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8135 (c == '.') || (c == '-') ||
8136 (c == '_') || (c == ':') ||
8137 (IS_COMBINING(c)) ||
8138 (IS_EXTENDER(c)))) {
8139 len += l;
8140 NEXTL(l);
8141 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +00008142 }
Daniel Veillard03226812004-11-01 14:55:21 +00008143 ret = xmlStrndup(cur, ctxt->cur - cur);
8144 ctxt->cur = cur;
8145 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00008146}
8147
8148/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008149 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008150 * @ctxt: the XPath Parser context
8151 *
8152 * [19] PathExpr ::= LocationPath
8153 * | FilterExpr
8154 * | FilterExpr '/' RelativeLocationPath
8155 * | FilterExpr '//' RelativeLocationPath
8156 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008157 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008158 * The / operator and // operators combine an arbitrary expression
8159 * and a relative location path. It is an error if the expression
8160 * does not evaluate to a node-set.
8161 * The / operator does composition in the same way as when / is
8162 * used in a location path. As in location paths, // is short for
8163 * /descendant-or-self::node()/.
8164 */
8165
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008166static void
8167xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008168 int lc = 1; /* Should we branch to LocationPath ? */
8169 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8170
8171 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008172 if ((CUR == '$') || (CUR == '(') ||
8173 (IS_ASCII_DIGIT(CUR)) ||
8174 (CUR == '\'') || (CUR == '"') ||
8175 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008176 lc = 0;
8177 } else if (CUR == '*') {
8178 /* relative or absolute location path */
8179 lc = 1;
8180 } else if (CUR == '/') {
8181 /* relative or absolute location path */
8182 lc = 1;
8183 } else if (CUR == '@') {
8184 /* relative abbreviated attribute location path */
8185 lc = 1;
8186 } else if (CUR == '.') {
8187 /* relative abbreviated attribute location path */
8188 lc = 1;
8189 } else {
8190 /*
8191 * Problem is finding if we have a name here whether it's:
8192 * - a nodetype
8193 * - a function call in which case it's followed by '('
8194 * - an axis in which case it's followed by ':'
8195 * - a element name
8196 * We do an a priori analysis here rather than having to
8197 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008198 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008199 * read/write/debug.
8200 */
8201 SKIP_BLANKS;
8202 name = xmlXPathScanName(ctxt);
8203 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8204#ifdef DEBUG_STEP
8205 xmlGenericError(xmlGenericErrorContext,
8206 "PathExpr: Axis\n");
8207#endif
8208 lc = 1;
8209 xmlFree(name);
8210 } else if (name != NULL) {
8211 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008212
8213
8214 while (NXT(len) != 0) {
8215 if (NXT(len) == '/') {
8216 /* element name */
8217#ifdef DEBUG_STEP
8218 xmlGenericError(xmlGenericErrorContext,
8219 "PathExpr: AbbrRelLocation\n");
8220#endif
8221 lc = 1;
8222 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008223 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008224 /* ignore blanks */
8225 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008226 } else if (NXT(len) == ':') {
8227#ifdef DEBUG_STEP
8228 xmlGenericError(xmlGenericErrorContext,
8229 "PathExpr: AbbrRelLocation\n");
8230#endif
8231 lc = 1;
8232 break;
8233 } else if ((NXT(len) == '(')) {
8234 /* Note Type or Function */
8235 if (xmlXPathIsNodeType(name)) {
8236#ifdef DEBUG_STEP
8237 xmlGenericError(xmlGenericErrorContext,
8238 "PathExpr: Type search\n");
8239#endif
8240 lc = 1;
8241 } else {
8242#ifdef DEBUG_STEP
8243 xmlGenericError(xmlGenericErrorContext,
8244 "PathExpr: function call\n");
8245#endif
8246 lc = 0;
8247 }
8248 break;
8249 } else if ((NXT(len) == '[')) {
8250 /* element name */
8251#ifdef DEBUG_STEP
8252 xmlGenericError(xmlGenericErrorContext,
8253 "PathExpr: AbbrRelLocation\n");
8254#endif
8255 lc = 1;
8256 break;
8257 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8258 (NXT(len) == '=')) {
8259 lc = 1;
8260 break;
8261 } else {
8262 lc = 1;
8263 break;
8264 }
8265 len++;
8266 }
8267 if (NXT(len) == 0) {
8268#ifdef DEBUG_STEP
8269 xmlGenericError(xmlGenericErrorContext,
8270 "PathExpr: AbbrRelLocation\n");
8271#endif
8272 /* element name */
8273 lc = 1;
8274 }
8275 xmlFree(name);
8276 } else {
William M. Brack08171912003-12-29 02:52:11 +00008277 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008278 XP_ERROR(XPATH_EXPR_ERROR);
8279 }
8280 }
8281
8282 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008283 if (CUR == '/') {
8284 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8285 } else {
8286 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008287 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008288 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008289 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008290 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008291 CHECK_ERROR;
8292 if ((CUR == '/') && (NXT(1) == '/')) {
8293 SKIP(2);
8294 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008295
8296 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8297 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8298 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8299
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008300 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008301 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008302 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008303 }
8304 }
8305 SKIP_BLANKS;
8306}
8307
8308/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008309 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008310 * @ctxt: the XPath Parser context
8311 *
8312 * [18] UnionExpr ::= PathExpr
8313 * | UnionExpr '|' PathExpr
8314 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008315 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008316 */
8317
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008318static void
8319xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8320 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008321 CHECK_ERROR;
8322 SKIP_BLANKS;
8323 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008324 int op1 = ctxt->comp->last;
8325 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008326
8327 NEXT;
8328 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008329 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008330
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008331 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8332
Owen Taylor3473f882001-02-23 17:55:21 +00008333 SKIP_BLANKS;
8334 }
Owen Taylor3473f882001-02-23 17:55:21 +00008335}
8336
8337/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008338 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008339 * @ctxt: the XPath Parser context
8340 *
8341 * [27] UnaryExpr ::= UnionExpr
8342 * | '-' UnaryExpr
8343 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008344 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008345 */
8346
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008347static void
8348xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008349 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008350 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008351
8352 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008353 while (CUR == '-') {
8354 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008355 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008356 NEXT;
8357 SKIP_BLANKS;
8358 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008359
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008360 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008361 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008362 if (found) {
8363 if (minus)
8364 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8365 else
8366 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008367 }
8368}
8369
8370/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008371 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008372 * @ctxt: the XPath Parser context
8373 *
8374 * [26] MultiplicativeExpr ::= UnaryExpr
8375 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8376 * | MultiplicativeExpr 'div' UnaryExpr
8377 * | MultiplicativeExpr 'mod' UnaryExpr
8378 * [34] MultiplyOperator ::= '*'
8379 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008380 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008381 */
8382
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008383static void
8384xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8385 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008386 CHECK_ERROR;
8387 SKIP_BLANKS;
8388 while ((CUR == '*') ||
8389 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8390 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8391 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008392 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008393
8394 if (CUR == '*') {
8395 op = 0;
8396 NEXT;
8397 } else if (CUR == 'd') {
8398 op = 1;
8399 SKIP(3);
8400 } else if (CUR == 'm') {
8401 op = 2;
8402 SKIP(3);
8403 }
8404 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008405 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008406 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008407 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008408 SKIP_BLANKS;
8409 }
8410}
8411
8412/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008413 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008414 * @ctxt: the XPath Parser context
8415 *
8416 * [25] AdditiveExpr ::= MultiplicativeExpr
8417 * | AdditiveExpr '+' MultiplicativeExpr
8418 * | AdditiveExpr '-' MultiplicativeExpr
8419 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008420 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008421 */
8422
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008423static void
8424xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008425
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008426 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008427 CHECK_ERROR;
8428 SKIP_BLANKS;
8429 while ((CUR == '+') || (CUR == '-')) {
8430 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008431 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008432
8433 if (CUR == '+') plus = 1;
8434 else plus = 0;
8435 NEXT;
8436 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008437 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008438 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008439 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008440 SKIP_BLANKS;
8441 }
8442}
8443
8444/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008445 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008446 * @ctxt: the XPath Parser context
8447 *
8448 * [24] RelationalExpr ::= AdditiveExpr
8449 * | RelationalExpr '<' AdditiveExpr
8450 * | RelationalExpr '>' AdditiveExpr
8451 * | RelationalExpr '<=' AdditiveExpr
8452 * | RelationalExpr '>=' AdditiveExpr
8453 *
8454 * A <= B > C is allowed ? Answer from James, yes with
8455 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8456 * which is basically what got implemented.
8457 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008458 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008459 * on the stack
8460 */
8461
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008462static void
8463xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8464 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008465 CHECK_ERROR;
8466 SKIP_BLANKS;
8467 while ((CUR == '<') ||
8468 (CUR == '>') ||
8469 ((CUR == '<') && (NXT(1) == '=')) ||
8470 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008471 int inf, strict;
8472 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008473
8474 if (CUR == '<') inf = 1;
8475 else inf = 0;
8476 if (NXT(1) == '=') strict = 0;
8477 else strict = 1;
8478 NEXT;
8479 if (!strict) NEXT;
8480 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008481 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008482 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008483 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008484 SKIP_BLANKS;
8485 }
8486}
8487
8488/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008489 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008490 * @ctxt: the XPath Parser context
8491 *
8492 * [23] EqualityExpr ::= RelationalExpr
8493 * | EqualityExpr '=' RelationalExpr
8494 * | EqualityExpr '!=' RelationalExpr
8495 *
8496 * A != B != C is allowed ? Answer from James, yes with
8497 * (RelationalExpr = RelationalExpr) = RelationalExpr
8498 * (RelationalExpr != RelationalExpr) != RelationalExpr
8499 * which is basically what got implemented.
8500 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008501 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008502 *
8503 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008504static void
8505xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8506 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008507 CHECK_ERROR;
8508 SKIP_BLANKS;
8509 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008510 int eq;
8511 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008512
8513 if (CUR == '=') eq = 1;
8514 else eq = 0;
8515 NEXT;
8516 if (!eq) NEXT;
8517 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008518 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008519 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008520 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008521 SKIP_BLANKS;
8522 }
8523}
8524
8525/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008526 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008527 * @ctxt: the XPath Parser context
8528 *
8529 * [22] AndExpr ::= EqualityExpr
8530 * | AndExpr 'and' EqualityExpr
8531 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008532 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008533 *
8534 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008535static void
8536xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8537 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008538 CHECK_ERROR;
8539 SKIP_BLANKS;
8540 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008541 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008542 SKIP(3);
8543 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008544 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008545 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008546 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008547 SKIP_BLANKS;
8548 }
8549}
8550
8551/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008552 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008553 * @ctxt: the XPath Parser context
8554 *
8555 * [14] Expr ::= OrExpr
8556 * [21] OrExpr ::= AndExpr
8557 * | OrExpr 'or' AndExpr
8558 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008559 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008560 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008561static void
8562xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8563 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008564 CHECK_ERROR;
8565 SKIP_BLANKS;
8566 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008567 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008568 SKIP(2);
8569 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008570 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008571 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008572 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8573 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008574 SKIP_BLANKS;
8575 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008576 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8577 /* more ops could be optimized too */
8578 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8579 }
Owen Taylor3473f882001-02-23 17:55:21 +00008580}
8581
8582/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008583 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008584 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008585 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008586 *
8587 * [8] Predicate ::= '[' PredicateExpr ']'
8588 * [9] PredicateExpr ::= Expr
8589 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008590 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008591 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008592static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008593xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008594 int op1 = ctxt->comp->last;
8595
8596 SKIP_BLANKS;
8597 if (CUR != '[') {
8598 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8599 }
8600 NEXT;
8601 SKIP_BLANKS;
8602
8603 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008604 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008605 CHECK_ERROR;
8606
8607 if (CUR != ']') {
8608 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8609 }
8610
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008611 if (filter)
8612 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8613 else
8614 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008615
8616 NEXT;
8617 SKIP_BLANKS;
8618}
8619
8620/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008621 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008622 * @ctxt: the XPath Parser context
8623 * @test: pointer to a xmlXPathTestVal
8624 * @type: pointer to a xmlXPathTypeVal
8625 * @prefix: placeholder for a possible name prefix
8626 *
8627 * [7] NodeTest ::= NameTest
8628 * | NodeType '(' ')'
8629 * | 'processing-instruction' '(' Literal ')'
8630 *
8631 * [37] NameTest ::= '*'
8632 * | NCName ':' '*'
8633 * | QName
8634 * [38] NodeType ::= 'comment'
8635 * | 'text'
8636 * | 'processing-instruction'
8637 * | 'node'
8638 *
William M. Brack08171912003-12-29 02:52:11 +00008639 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00008640 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008641static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008642xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8643 xmlXPathTypeVal *type, const xmlChar **prefix,
8644 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008645 int blanks;
8646
8647 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8648 STRANGE;
8649 return(NULL);
8650 }
William M. Brack78637da2003-07-31 14:47:38 +00008651 *type = (xmlXPathTypeVal) 0;
8652 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008653 *prefix = NULL;
8654 SKIP_BLANKS;
8655
8656 if ((name == NULL) && (CUR == '*')) {
8657 /*
8658 * All elements
8659 */
8660 NEXT;
8661 *test = NODE_TEST_ALL;
8662 return(NULL);
8663 }
8664
8665 if (name == NULL)
8666 name = xmlXPathParseNCName(ctxt);
8667 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00008668 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00008669 }
8670
William M. Brack76e95df2003-10-18 16:20:14 +00008671 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008672 SKIP_BLANKS;
8673 if (CUR == '(') {
8674 NEXT;
8675 /*
8676 * NodeType or PI search
8677 */
8678 if (xmlStrEqual(name, BAD_CAST "comment"))
8679 *type = NODE_TYPE_COMMENT;
8680 else if (xmlStrEqual(name, BAD_CAST "node"))
8681 *type = NODE_TYPE_NODE;
8682 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8683 *type = NODE_TYPE_PI;
8684 else if (xmlStrEqual(name, BAD_CAST "text"))
8685 *type = NODE_TYPE_TEXT;
8686 else {
8687 if (name != NULL)
8688 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +00008689 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00008690 }
8691
8692 *test = NODE_TEST_TYPE;
8693
8694 SKIP_BLANKS;
8695 if (*type == NODE_TYPE_PI) {
8696 /*
8697 * Specific case: search a PI by name.
8698 */
Owen Taylor3473f882001-02-23 17:55:21 +00008699 if (name != NULL)
8700 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008701 name = NULL;
8702 if (CUR != ')') {
8703 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +00008704 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008705 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008706 SKIP_BLANKS;
8707 }
Owen Taylor3473f882001-02-23 17:55:21 +00008708 }
8709 if (CUR != ')') {
8710 if (name != NULL)
8711 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +00008712 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00008713 }
8714 NEXT;
8715 return(name);
8716 }
8717 *test = NODE_TEST_NAME;
8718 if ((!blanks) && (CUR == ':')) {
8719 NEXT;
8720
8721 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008722 * Since currently the parser context don't have a
8723 * namespace list associated:
8724 * The namespace name for this prefix can be computed
8725 * only at evaluation time. The compilation is done
8726 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008727 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008728#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008729 *prefix = xmlXPathNsLookup(ctxt->context, name);
8730 if (name != NULL)
8731 xmlFree(name);
8732 if (*prefix == NULL) {
8733 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8734 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008735#else
8736 *prefix = name;
8737#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008738
8739 if (CUR == '*') {
8740 /*
8741 * All elements
8742 */
8743 NEXT;
8744 *test = NODE_TEST_ALL;
8745 return(NULL);
8746 }
8747
8748 name = xmlXPathParseNCName(ctxt);
8749 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00008750 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00008751 }
8752 }
8753 return(name);
8754}
8755
8756/**
8757 * xmlXPathIsAxisName:
8758 * @name: a preparsed name token
8759 *
8760 * [6] AxisName ::= 'ancestor'
8761 * | 'ancestor-or-self'
8762 * | 'attribute'
8763 * | 'child'
8764 * | 'descendant'
8765 * | 'descendant-or-self'
8766 * | 'following'
8767 * | 'following-sibling'
8768 * | 'namespace'
8769 * | 'parent'
8770 * | 'preceding'
8771 * | 'preceding-sibling'
8772 * | 'self'
8773 *
8774 * Returns the axis or 0
8775 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008776static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008777xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008778 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008779 switch (name[0]) {
8780 case 'a':
8781 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8782 ret = AXIS_ANCESTOR;
8783 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8784 ret = AXIS_ANCESTOR_OR_SELF;
8785 if (xmlStrEqual(name, BAD_CAST "attribute"))
8786 ret = AXIS_ATTRIBUTE;
8787 break;
8788 case 'c':
8789 if (xmlStrEqual(name, BAD_CAST "child"))
8790 ret = AXIS_CHILD;
8791 break;
8792 case 'd':
8793 if (xmlStrEqual(name, BAD_CAST "descendant"))
8794 ret = AXIS_DESCENDANT;
8795 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8796 ret = AXIS_DESCENDANT_OR_SELF;
8797 break;
8798 case 'f':
8799 if (xmlStrEqual(name, BAD_CAST "following"))
8800 ret = AXIS_FOLLOWING;
8801 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8802 ret = AXIS_FOLLOWING_SIBLING;
8803 break;
8804 case 'n':
8805 if (xmlStrEqual(name, BAD_CAST "namespace"))
8806 ret = AXIS_NAMESPACE;
8807 break;
8808 case 'p':
8809 if (xmlStrEqual(name, BAD_CAST "parent"))
8810 ret = AXIS_PARENT;
8811 if (xmlStrEqual(name, BAD_CAST "preceding"))
8812 ret = AXIS_PRECEDING;
8813 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8814 ret = AXIS_PRECEDING_SIBLING;
8815 break;
8816 case 's':
8817 if (xmlStrEqual(name, BAD_CAST "self"))
8818 ret = AXIS_SELF;
8819 break;
8820 }
8821 return(ret);
8822}
8823
8824/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008825 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008826 * @ctxt: the XPath Parser context
8827 *
8828 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8829 * | AbbreviatedStep
8830 *
8831 * [12] AbbreviatedStep ::= '.' | '..'
8832 *
8833 * [5] AxisSpecifier ::= AxisName '::'
8834 * | AbbreviatedAxisSpecifier
8835 *
8836 * [13] AbbreviatedAxisSpecifier ::= '@'?
8837 *
8838 * Modified for XPtr range support as:
8839 *
8840 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8841 * | AbbreviatedStep
8842 * | 'range-to' '(' Expr ')' Predicate*
8843 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008844 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008845 * A location step of . is short for self::node(). This is
8846 * particularly useful in conjunction with //. For example, the
8847 * location path .//para is short for
8848 * self::node()/descendant-or-self::node()/child::para
8849 * and so will select all para descendant elements of the context
8850 * node.
8851 * Similarly, a location step of .. is short for parent::node().
8852 * For example, ../title is short for parent::node()/child::title
8853 * and so will select the title children of the parent of the context
8854 * node.
8855 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008856static void
8857xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008858#ifdef LIBXML_XPTR_ENABLED
8859 int rangeto = 0;
8860 int op2 = -1;
8861#endif
8862
Owen Taylor3473f882001-02-23 17:55:21 +00008863 SKIP_BLANKS;
8864 if ((CUR == '.') && (NXT(1) == '.')) {
8865 SKIP(2);
8866 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008867 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8868 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008869 } else if (CUR == '.') {
8870 NEXT;
8871 SKIP_BLANKS;
8872 } else {
8873 xmlChar *name = NULL;
8874 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +00008875 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +00008876 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +00008877 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008878 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008879
8880 /*
8881 * The modification needed for XPointer change to the production
8882 */
8883#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008884 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008885 name = xmlXPathParseNCName(ctxt);
8886 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008887 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008888 xmlFree(name);
8889 SKIP_BLANKS;
8890 if (CUR != '(') {
8891 XP_ERROR(XPATH_EXPR_ERROR);
8892 }
8893 NEXT;
8894 SKIP_BLANKS;
8895
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008896 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008897 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008898 CHECK_ERROR;
8899
8900 SKIP_BLANKS;
8901 if (CUR != ')') {
8902 XP_ERROR(XPATH_EXPR_ERROR);
8903 }
8904 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008905 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008906 goto eval_predicates;
8907 }
8908 }
8909#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008910 if (CUR == '*') {
8911 axis = AXIS_CHILD;
8912 } else {
8913 if (name == NULL)
8914 name = xmlXPathParseNCName(ctxt);
8915 if (name != NULL) {
8916 axis = xmlXPathIsAxisName(name);
8917 if (axis != 0) {
8918 SKIP_BLANKS;
8919 if ((CUR == ':') && (NXT(1) == ':')) {
8920 SKIP(2);
8921 xmlFree(name);
8922 name = NULL;
8923 } else {
8924 /* an element name can conflict with an axis one :-\ */
8925 axis = AXIS_CHILD;
8926 }
Owen Taylor3473f882001-02-23 17:55:21 +00008927 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008928 axis = AXIS_CHILD;
8929 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008930 } else if (CUR == '@') {
8931 NEXT;
8932 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008933 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008934 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008935 }
Owen Taylor3473f882001-02-23 17:55:21 +00008936 }
8937
8938 CHECK_ERROR;
8939
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008940 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008941 if (test == 0)
8942 return;
8943
Daniel Veillarded6c5492005-07-23 15:00:22 +00008944 if ((prefix != NULL) && (ctxt->context != NULL) &&
8945 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
8946 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
8947 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
8948 }
8949 }
Owen Taylor3473f882001-02-23 17:55:21 +00008950#ifdef DEBUG_STEP
8951 xmlGenericError(xmlGenericErrorContext,
8952 "Basis : computing new set\n");
8953#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008954
Owen Taylor3473f882001-02-23 17:55:21 +00008955#ifdef DEBUG_STEP
8956 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008957 if (ctxt->value == NULL)
8958 xmlGenericError(xmlGenericErrorContext, "no value\n");
8959 else if (ctxt->value->nodesetval == NULL)
8960 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8961 else
8962 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008963#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008964
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008965#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008966eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008967#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008968 op1 = ctxt->comp->last;
8969 ctxt->comp->last = -1;
8970
Owen Taylor3473f882001-02-23 17:55:21 +00008971 SKIP_BLANKS;
8972 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008973 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008974 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008975
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008976#ifdef LIBXML_XPTR_ENABLED
8977 if (rangeto) {
8978 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8979 } else
8980#endif
8981 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8982 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008983
Owen Taylor3473f882001-02-23 17:55:21 +00008984 }
8985#ifdef DEBUG_STEP
8986 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008987 if (ctxt->value == NULL)
8988 xmlGenericError(xmlGenericErrorContext, "no value\n");
8989 else if (ctxt->value->nodesetval == NULL)
8990 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8991 else
8992 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8993 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008994#endif
8995}
8996
8997/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008998 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008999 * @ctxt: the XPath Parser context
9000 *
9001 * [3] RelativeLocationPath ::= Step
9002 * | RelativeLocationPath '/' Step
9003 * | AbbreviatedRelativeLocationPath
9004 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
9005 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009006 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00009007 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009008static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009009xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00009010(xmlXPathParserContextPtr ctxt) {
9011 SKIP_BLANKS;
9012 if ((CUR == '/') && (NXT(1) == '/')) {
9013 SKIP(2);
9014 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009015 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9016 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009017 } else if (CUR == '/') {
9018 NEXT;
9019 SKIP_BLANKS;
9020 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009021 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009022 SKIP_BLANKS;
9023 while (CUR == '/') {
9024 if ((CUR == '/') && (NXT(1) == '/')) {
9025 SKIP(2);
9026 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009027 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00009028 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009029 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009030 } else if (CUR == '/') {
9031 NEXT;
9032 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009033 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009034 }
9035 SKIP_BLANKS;
9036 }
9037}
9038
9039/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009040 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00009041 * @ctxt: the XPath Parser context
9042 *
9043 * [1] LocationPath ::= RelativeLocationPath
9044 * | AbsoluteLocationPath
9045 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
9046 * | AbbreviatedAbsoluteLocationPath
9047 * [10] AbbreviatedAbsoluteLocationPath ::=
9048 * '//' RelativeLocationPath
9049 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009050 * Compile a location path
9051 *
Owen Taylor3473f882001-02-23 17:55:21 +00009052 * // is short for /descendant-or-self::node()/. For example,
9053 * //para is short for /descendant-or-self::node()/child::para and
9054 * so will select any para element in the document (even a para element
9055 * that is a document element will be selected by //para since the
9056 * document element node is a child of the root node); div//para is
9057 * short for div/descendant-or-self::node()/child::para and so will
9058 * select all para descendants of div children.
9059 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009060static void
9061xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009062 SKIP_BLANKS;
9063 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009064 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009065 } else {
9066 while (CUR == '/') {
9067 if ((CUR == '/') && (NXT(1) == '/')) {
9068 SKIP(2);
9069 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009070 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9071 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009072 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009073 } else if (CUR == '/') {
9074 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00009075 SKIP_BLANKS;
9076 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +00009077 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00009078 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009079 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009080 }
9081 }
9082 }
9083}
9084
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009085/************************************************************************
9086 * *
9087 * XPath precompiled expression evaluation *
9088 * *
9089 ************************************************************************/
9090
Daniel Veillardf06307e2001-07-03 10:35:50 +00009091static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009092xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
9093
9094/**
9095 * xmlXPathNodeCollectAndTest:
9096 * @ctxt: the XPath Parser context
9097 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009098 * @first: pointer to the first element in document order
9099 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009100 *
9101 * This is the function implementing a step: based on the current list
9102 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009103 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009104 *
9105 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00009106 *
William M. Brack08171912003-12-29 02:52:11 +00009107 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009108 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009109static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009110xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009111 xmlXPathStepOpPtr op,
9112 xmlNodePtr * first, xmlNodePtr * last)
9113{
William M. Brack78637da2003-07-31 14:47:38 +00009114 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9115 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9116 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009117 const xmlChar *prefix = op->value4;
9118 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009119 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009120
9121#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009122 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009123#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009124 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009125 xmlNodeSetPtr ret, list;
9126 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009127 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00009128 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009129 xmlNodePtr cur = NULL;
9130 xmlXPathObjectPtr obj;
9131 xmlNodeSetPtr nodelist;
9132 xmlNodePtr tmp;
9133
Daniel Veillardf06307e2001-07-03 10:35:50 +00009134 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009135 obj = valuePop(ctxt);
9136 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009137 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009138 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009139 URI = xmlXPathNsLookup(ctxt->context, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009140 if (URI == NULL) {
9141 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009142 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009143 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009144 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009145#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009146 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009147#endif
9148 switch (axis) {
9149 case AXIS_ANCESTOR:
9150#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009151 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009152#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009153 first = NULL;
9154 next = xmlXPathNextAncestor;
9155 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009156 case AXIS_ANCESTOR_OR_SELF:
9157#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009158 xmlGenericError(xmlGenericErrorContext,
9159 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009160#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009161 first = NULL;
9162 next = xmlXPathNextAncestorOrSelf;
9163 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009164 case AXIS_ATTRIBUTE:
9165#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009166 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009167#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009168 first = NULL;
9169 last = NULL;
9170 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009171 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009172 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009173 case AXIS_CHILD:
9174#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009175 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009176#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009177 last = NULL;
9178 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009179 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009180 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009181 case AXIS_DESCENDANT:
9182#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009183 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009184#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009185 last = NULL;
9186 next = xmlXPathNextDescendant;
9187 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009188 case AXIS_DESCENDANT_OR_SELF:
9189#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009190 xmlGenericError(xmlGenericErrorContext,
9191 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009192#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009193 last = NULL;
9194 next = xmlXPathNextDescendantOrSelf;
9195 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009196 case AXIS_FOLLOWING:
9197#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009198 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009199#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009200 last = NULL;
9201 next = xmlXPathNextFollowing;
9202 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009203 case AXIS_FOLLOWING_SIBLING:
9204#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009205 xmlGenericError(xmlGenericErrorContext,
9206 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009207#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009208 last = NULL;
9209 next = xmlXPathNextFollowingSibling;
9210 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009211 case AXIS_NAMESPACE:
9212#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009213 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009214#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009215 first = NULL;
9216 last = NULL;
9217 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009218 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009219 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009220 case AXIS_PARENT:
9221#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009222 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009223#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009224 first = NULL;
9225 next = xmlXPathNextParent;
9226 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009227 case AXIS_PRECEDING:
9228#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009229 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009230#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009231 first = NULL;
9232 next = xmlXPathNextPrecedingInternal;
9233 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009234 case AXIS_PRECEDING_SIBLING:
9235#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009236 xmlGenericError(xmlGenericErrorContext,
9237 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009238#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009239 first = NULL;
9240 next = xmlXPathNextPrecedingSibling;
9241 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009242 case AXIS_SELF:
9243#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009244 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009245#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009246 first = NULL;
9247 last = NULL;
9248 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009249 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009250 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009251 }
William M. Brack2c19a7b2005-04-10 01:03:23 +00009252 if (next == NULL) {
9253 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009254 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009255 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009256
9257 nodelist = obj->nodesetval;
9258 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009259 xmlXPathFreeObject(obj);
9260 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9261 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009262 }
9263 addNode = xmlXPathNodeSetAddUnique;
9264 ret = NULL;
9265#ifdef DEBUG_STEP
9266 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009267 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009268 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009269 case NODE_TEST_NONE:
9270 xmlGenericError(xmlGenericErrorContext,
9271 " searching for none !!!\n");
9272 break;
9273 case NODE_TEST_TYPE:
9274 xmlGenericError(xmlGenericErrorContext,
9275 " searching for type %d\n", type);
9276 break;
9277 case NODE_TEST_PI:
9278 xmlGenericError(xmlGenericErrorContext,
9279 " searching for PI !!!\n");
9280 break;
9281 case NODE_TEST_ALL:
9282 xmlGenericError(xmlGenericErrorContext,
9283 " searching for *\n");
9284 break;
9285 case NODE_TEST_NS:
9286 xmlGenericError(xmlGenericErrorContext,
9287 " searching for namespace %s\n",
9288 prefix);
9289 break;
9290 case NODE_TEST_NAME:
9291 xmlGenericError(xmlGenericErrorContext,
9292 " searching for name %s\n", name);
9293 if (prefix != NULL)
9294 xmlGenericError(xmlGenericErrorContext,
9295 " with namespace %s\n", prefix);
9296 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009297 }
9298 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9299#endif
9300 /*
9301 * 2.3 Node Tests
9302 * - For the attribute axis, the principal node type is attribute.
9303 * - For the namespace axis, the principal node type is namespace.
9304 * - For other axes, the principal node type is element.
9305 *
9306 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009307 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009308 * select all element children of the context node
9309 */
9310 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009311 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009312 ctxt->context->node = nodelist->nodeTab[i];
9313
Daniel Veillardf06307e2001-07-03 10:35:50 +00009314 cur = NULL;
9315 list = xmlXPathNodeSetCreate(NULL);
9316 do {
9317 cur = next(ctxt, cur);
9318 if (cur == NULL)
9319 break;
9320 if ((first != NULL) && (*first == cur))
9321 break;
9322 if (((t % 256) == 0) &&
9323 (first != NULL) && (*first != NULL) &&
9324 (xmlXPathCmpNodes(*first, cur) >= 0))
9325 break;
9326 if ((last != NULL) && (*last == cur))
9327 break;
9328 if (((t % 256) == 0) &&
9329 (last != NULL) && (*last != NULL) &&
9330 (xmlXPathCmpNodes(cur, *last) >= 0))
9331 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009332 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009333#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009334 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9335#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009336 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009337 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009338 ctxt->context->node = tmp;
William M. Brack2c19a7b2005-04-10 01:03:23 +00009339 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009340 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009341 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009342 if ((cur->type == type) ||
9343 ((type == NODE_TYPE_NODE) &&
9344 ((cur->type == XML_DOCUMENT_NODE) ||
9345 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9346 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009347 (cur->type == XML_NAMESPACE_DECL) ||
9348 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009349 (cur->type == XML_PI_NODE) ||
9350 (cur->type == XML_COMMENT_NODE) ||
9351 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009352 (cur->type == XML_TEXT_NODE))) ||
9353 ((type == NODE_TYPE_TEXT) &&
9354 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009355#ifdef DEBUG_STEP
9356 n++;
9357#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009358 addNode(list, cur);
9359 }
9360 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009361 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009362 if (cur->type == XML_PI_NODE) {
9363 if ((name != NULL) &&
9364 (!xmlStrEqual(name, cur->name)))
9365 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009366#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009367 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009368#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009369 addNode(list, cur);
9370 }
9371 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009372 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009373 if (axis == AXIS_ATTRIBUTE) {
9374 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009375#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009376 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009377#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009378 addNode(list, cur);
9379 }
9380 } else if (axis == AXIS_NAMESPACE) {
9381 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009382#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009383 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009384#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009385 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9386 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009387 }
9388 } else {
9389 if (cur->type == XML_ELEMENT_NODE) {
9390 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009391#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009392 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009393#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009394 addNode(list, cur);
9395 } else if ((cur->ns != NULL) &&
9396 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009397#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009398 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009399#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009400 addNode(list, cur);
9401 }
9402 }
9403 }
9404 break;
9405 case NODE_TEST_NS:{
9406 TODO;
9407 break;
9408 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009409 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009410 switch (cur->type) {
9411 case XML_ELEMENT_NODE:
9412 if (xmlStrEqual(name, cur->name)) {
9413 if (prefix == NULL) {
9414 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009415#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009416 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009417#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009418 addNode(list, cur);
9419 }
9420 } else {
9421 if ((cur->ns != NULL) &&
9422 (xmlStrEqual(URI,
9423 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009424#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009425 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009426#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009427 addNode(list, cur);
9428 }
9429 }
9430 }
9431 break;
9432 case XML_ATTRIBUTE_NODE:{
9433 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009434
Daniel Veillardf06307e2001-07-03 10:35:50 +00009435 if (xmlStrEqual(name, attr->name)) {
9436 if (prefix == NULL) {
9437 if ((attr->ns == NULL) ||
9438 (attr->ns->prefix == NULL)) {
9439#ifdef DEBUG_STEP
9440 n++;
9441#endif
9442 addNode(list,
9443 (xmlNodePtr) attr);
9444 }
9445 } else {
9446 if ((attr->ns != NULL) &&
9447 (xmlStrEqual(URI,
9448 attr->ns->
9449 href))) {
9450#ifdef DEBUG_STEP
9451 n++;
9452#endif
9453 addNode(list,
9454 (xmlNodePtr) attr);
9455 }
9456 }
9457 }
9458 break;
9459 }
9460 case XML_NAMESPACE_DECL:
9461 if (cur->type == XML_NAMESPACE_DECL) {
9462 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009463
Daniel Veillardf06307e2001-07-03 10:35:50 +00009464 if ((ns->prefix != NULL) && (name != NULL)
9465 && (xmlStrEqual(ns->prefix, name))) {
9466#ifdef DEBUG_STEP
9467 n++;
9468#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009469 xmlXPathNodeSetAddNs(list,
9470 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009471 }
9472 }
9473 break;
9474 default:
9475 break;
9476 }
9477 break;
9478 break;
9479 }
9480 } while (cur != NULL);
9481
9482 /*
9483 * If there is some predicate filtering do it now
9484 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009485 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009486 xmlXPathObjectPtr obj2;
9487
9488 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9489 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9490 CHECK_TYPE0(XPATH_NODESET);
9491 obj2 = valuePop(ctxt);
9492 list = obj2->nodesetval;
9493 obj2->nodesetval = NULL;
9494 xmlXPathFreeObject(obj2);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009495 if (ctxt->error != XPATH_EXPRESSION_OK) {
9496 xmlXPathFreeObject(obj);
9497 xmlXPathFreeNodeSet(list);
9498 return(0);
9499 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009500 }
9501 if (ret == NULL) {
9502 ret = list;
9503 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009504 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009505 xmlXPathFreeNodeSet(list);
9506 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009507 }
9508 ctxt->context->node = tmp;
9509#ifdef DEBUG_STEP
9510 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009511 "\nExamined %d nodes, found %d nodes at that step\n",
9512 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009513#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009514 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009515 if ((obj->boolval) && (obj->user != NULL)) {
9516 ctxt->value->boolval = 1;
9517 ctxt->value->user = obj->user;
9518 obj->user = NULL;
9519 obj->boolval = 0;
9520 }
9521 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009522 return(t);
9523}
9524
9525/**
9526 * xmlXPathNodeCollectAndTestNth:
9527 * @ctxt: the XPath Parser context
9528 * @op: the XPath precompiled step operation
9529 * @indx: the index to collect
9530 * @first: pointer to the first element in document order
9531 * @last: pointer to the last element in document order
9532 *
9533 * This is the function implementing a step: based on the current list
9534 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009535 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009536 *
9537 * Pushes the new NodeSet resulting from the search.
9538 * Returns the number of node traversed
9539 */
9540static int
9541xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9542 xmlXPathStepOpPtr op, int indx,
9543 xmlNodePtr * first, xmlNodePtr * last)
9544{
William M. Brack78637da2003-07-31 14:47:38 +00009545 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9546 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9547 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009548 const xmlChar *prefix = op->value4;
9549 const xmlChar *name = op->value5;
9550 const xmlChar *URI = NULL;
9551 int n = 0, t = 0;
9552
9553 int i;
9554 xmlNodeSetPtr list;
9555 xmlXPathTraversalFunction next = NULL;
9556 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9557 xmlNodePtr cur = NULL;
9558 xmlXPathObjectPtr obj;
9559 xmlNodeSetPtr nodelist;
9560 xmlNodePtr tmp;
9561
9562 CHECK_TYPE0(XPATH_NODESET);
9563 obj = valuePop(ctxt);
9564 addNode = xmlXPathNodeSetAdd;
9565 if (prefix != NULL) {
9566 URI = xmlXPathNsLookup(ctxt->context, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009567 if (URI == NULL) {
9568 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009569 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009570 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009571 }
9572#ifdef DEBUG_STEP_NTH
9573 xmlGenericError(xmlGenericErrorContext, "new step : ");
9574 if (first != NULL) {
9575 if (*first != NULL)
9576 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9577 (*first)->name);
9578 else
9579 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9580 }
9581 if (last != NULL) {
9582 if (*last != NULL)
9583 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9584 (*last)->name);
9585 else
9586 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9587 }
9588#endif
9589 switch (axis) {
9590 case AXIS_ANCESTOR:
9591#ifdef DEBUG_STEP_NTH
9592 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9593#endif
9594 first = NULL;
9595 next = xmlXPathNextAncestor;
9596 break;
9597 case AXIS_ANCESTOR_OR_SELF:
9598#ifdef DEBUG_STEP_NTH
9599 xmlGenericError(xmlGenericErrorContext,
9600 "axis 'ancestors-or-self' ");
9601#endif
9602 first = NULL;
9603 next = xmlXPathNextAncestorOrSelf;
9604 break;
9605 case AXIS_ATTRIBUTE:
9606#ifdef DEBUG_STEP_NTH
9607 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9608#endif
9609 first = NULL;
9610 last = NULL;
9611 next = xmlXPathNextAttribute;
9612 break;
9613 case AXIS_CHILD:
9614#ifdef DEBUG_STEP_NTH
9615 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9616#endif
9617 last = NULL;
9618 next = xmlXPathNextChild;
9619 break;
9620 case AXIS_DESCENDANT:
9621#ifdef DEBUG_STEP_NTH
9622 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9623#endif
9624 last = NULL;
9625 next = xmlXPathNextDescendant;
9626 break;
9627 case AXIS_DESCENDANT_OR_SELF:
9628#ifdef DEBUG_STEP_NTH
9629 xmlGenericError(xmlGenericErrorContext,
9630 "axis 'descendant-or-self' ");
9631#endif
9632 last = NULL;
9633 next = xmlXPathNextDescendantOrSelf;
9634 break;
9635 case AXIS_FOLLOWING:
9636#ifdef DEBUG_STEP_NTH
9637 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9638#endif
9639 last = NULL;
9640 next = xmlXPathNextFollowing;
9641 break;
9642 case AXIS_FOLLOWING_SIBLING:
9643#ifdef DEBUG_STEP_NTH
9644 xmlGenericError(xmlGenericErrorContext,
9645 "axis 'following-siblings' ");
9646#endif
9647 last = NULL;
9648 next = xmlXPathNextFollowingSibling;
9649 break;
9650 case AXIS_NAMESPACE:
9651#ifdef DEBUG_STEP_NTH
9652 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9653#endif
9654 last = NULL;
9655 first = NULL;
9656 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9657 break;
9658 case AXIS_PARENT:
9659#ifdef DEBUG_STEP_NTH
9660 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9661#endif
9662 first = NULL;
9663 next = xmlXPathNextParent;
9664 break;
9665 case AXIS_PRECEDING:
9666#ifdef DEBUG_STEP_NTH
9667 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9668#endif
9669 first = NULL;
9670 next = xmlXPathNextPrecedingInternal;
9671 break;
9672 case AXIS_PRECEDING_SIBLING:
9673#ifdef DEBUG_STEP_NTH
9674 xmlGenericError(xmlGenericErrorContext,
9675 "axis 'preceding-sibling' ");
9676#endif
9677 first = NULL;
9678 next = xmlXPathNextPrecedingSibling;
9679 break;
9680 case AXIS_SELF:
9681#ifdef DEBUG_STEP_NTH
9682 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9683#endif
9684 first = NULL;
9685 last = NULL;
9686 next = xmlXPathNextSelf;
9687 break;
9688 }
William M. Brack2c19a7b2005-04-10 01:03:23 +00009689 if (next == NULL) {
9690 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009691 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009692 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009693
9694 nodelist = obj->nodesetval;
9695 if (nodelist == NULL) {
9696 xmlXPathFreeObject(obj);
9697 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9698 return(0);
9699 }
9700 addNode = xmlXPathNodeSetAddUnique;
9701#ifdef DEBUG_STEP_NTH
9702 xmlGenericError(xmlGenericErrorContext,
9703 " context contains %d nodes\n", nodelist->nodeNr);
9704 switch (test) {
9705 case NODE_TEST_NONE:
9706 xmlGenericError(xmlGenericErrorContext,
9707 " searching for none !!!\n");
9708 break;
9709 case NODE_TEST_TYPE:
9710 xmlGenericError(xmlGenericErrorContext,
9711 " searching for type %d\n", type);
9712 break;
9713 case NODE_TEST_PI:
9714 xmlGenericError(xmlGenericErrorContext,
9715 " searching for PI !!!\n");
9716 break;
9717 case NODE_TEST_ALL:
9718 xmlGenericError(xmlGenericErrorContext,
9719 " searching for *\n");
9720 break;
9721 case NODE_TEST_NS:
9722 xmlGenericError(xmlGenericErrorContext,
9723 " searching for namespace %s\n",
9724 prefix);
9725 break;
9726 case NODE_TEST_NAME:
9727 xmlGenericError(xmlGenericErrorContext,
9728 " searching for name %s\n", name);
9729 if (prefix != NULL)
9730 xmlGenericError(xmlGenericErrorContext,
9731 " with namespace %s\n", prefix);
9732 break;
9733 }
9734 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9735#endif
9736 /*
9737 * 2.3 Node Tests
9738 * - For the attribute axis, the principal node type is attribute.
9739 * - For the namespace axis, the principal node type is namespace.
9740 * - For other axes, the principal node type is element.
9741 *
9742 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009743 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009744 * select all element children of the context node
9745 */
9746 tmp = ctxt->context->node;
9747 list = xmlXPathNodeSetCreate(NULL);
9748 for (i = 0; i < nodelist->nodeNr; i++) {
9749 ctxt->context->node = nodelist->nodeTab[i];
9750
9751 cur = NULL;
9752 n = 0;
9753 do {
9754 cur = next(ctxt, cur);
9755 if (cur == NULL)
9756 break;
9757 if ((first != NULL) && (*first == cur))
9758 break;
9759 if (((t % 256) == 0) &&
9760 (first != NULL) && (*first != NULL) &&
9761 (xmlXPathCmpNodes(*first, cur) >= 0))
9762 break;
9763 if ((last != NULL) && (*last == cur))
9764 break;
9765 if (((t % 256) == 0) &&
9766 (last != NULL) && (*last != NULL) &&
9767 (xmlXPathCmpNodes(cur, *last) >= 0))
9768 break;
9769 t++;
9770 switch (test) {
9771 case NODE_TEST_NONE:
9772 ctxt->context->node = tmp;
9773 STRANGE return(0);
9774 case NODE_TEST_TYPE:
9775 if ((cur->type == type) ||
9776 ((type == NODE_TYPE_NODE) &&
9777 ((cur->type == XML_DOCUMENT_NODE) ||
9778 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9779 (cur->type == XML_ELEMENT_NODE) ||
9780 (cur->type == XML_PI_NODE) ||
9781 (cur->type == XML_COMMENT_NODE) ||
9782 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009783 (cur->type == XML_TEXT_NODE))) ||
9784 ((type == NODE_TYPE_TEXT) &&
9785 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009786 n++;
9787 if (n == indx)
9788 addNode(list, cur);
9789 }
9790 break;
9791 case NODE_TEST_PI:
9792 if (cur->type == XML_PI_NODE) {
9793 if ((name != NULL) &&
9794 (!xmlStrEqual(name, cur->name)))
9795 break;
9796 n++;
9797 if (n == indx)
9798 addNode(list, cur);
9799 }
9800 break;
9801 case NODE_TEST_ALL:
9802 if (axis == AXIS_ATTRIBUTE) {
9803 if (cur->type == XML_ATTRIBUTE_NODE) {
9804 n++;
9805 if (n == indx)
9806 addNode(list, cur);
9807 }
9808 } else if (axis == AXIS_NAMESPACE) {
9809 if (cur->type == XML_NAMESPACE_DECL) {
9810 n++;
9811 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009812 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9813 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009814 }
9815 } else {
9816 if (cur->type == XML_ELEMENT_NODE) {
9817 if (prefix == NULL) {
9818 n++;
9819 if (n == indx)
9820 addNode(list, cur);
9821 } else if ((cur->ns != NULL) &&
9822 (xmlStrEqual(URI, cur->ns->href))) {
9823 n++;
9824 if (n == indx)
9825 addNode(list, cur);
9826 }
9827 }
9828 }
9829 break;
9830 case NODE_TEST_NS:{
9831 TODO;
9832 break;
9833 }
9834 case NODE_TEST_NAME:
9835 switch (cur->type) {
9836 case XML_ELEMENT_NODE:
9837 if (xmlStrEqual(name, cur->name)) {
9838 if (prefix == NULL) {
9839 if (cur->ns == NULL) {
9840 n++;
9841 if (n == indx)
9842 addNode(list, cur);
9843 }
9844 } else {
9845 if ((cur->ns != NULL) &&
9846 (xmlStrEqual(URI,
9847 cur->ns->href))) {
9848 n++;
9849 if (n == indx)
9850 addNode(list, cur);
9851 }
9852 }
9853 }
9854 break;
9855 case XML_ATTRIBUTE_NODE:{
9856 xmlAttrPtr attr = (xmlAttrPtr) cur;
9857
9858 if (xmlStrEqual(name, attr->name)) {
9859 if (prefix == NULL) {
9860 if ((attr->ns == NULL) ||
9861 (attr->ns->prefix == NULL)) {
9862 n++;
9863 if (n == indx)
9864 addNode(list, cur);
9865 }
9866 } else {
9867 if ((attr->ns != NULL) &&
9868 (xmlStrEqual(URI,
9869 attr->ns->
9870 href))) {
9871 n++;
9872 if (n == indx)
9873 addNode(list, cur);
9874 }
9875 }
9876 }
9877 break;
9878 }
9879 case XML_NAMESPACE_DECL:
9880 if (cur->type == XML_NAMESPACE_DECL) {
9881 xmlNsPtr ns = (xmlNsPtr) cur;
9882
9883 if ((ns->prefix != NULL) && (name != NULL)
9884 && (xmlStrEqual(ns->prefix, name))) {
9885 n++;
9886 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009887 xmlXPathNodeSetAddNs(list,
9888 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009889 }
9890 }
9891 break;
9892 default:
9893 break;
9894 }
9895 break;
9896 break;
9897 }
9898 } while (n < indx);
9899 }
9900 ctxt->context->node = tmp;
9901#ifdef DEBUG_STEP_NTH
9902 xmlGenericError(xmlGenericErrorContext,
9903 "\nExamined %d nodes, found %d nodes at that step\n",
9904 t, list->nodeNr);
9905#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009906 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009907 if ((obj->boolval) && (obj->user != NULL)) {
9908 ctxt->value->boolval = 1;
9909 ctxt->value->user = obj->user;
9910 obj->user = NULL;
9911 obj->boolval = 0;
9912 }
9913 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009914 return(t);
9915}
9916
9917/**
9918 * xmlXPathCompOpEvalFirst:
9919 * @ctxt: the XPath parser context with the compiled expression
9920 * @op: an XPath compiled operation
9921 * @first: the first elem found so far
9922 *
9923 * Evaluate the Precompiled XPath operation searching only the first
9924 * element in document order
9925 *
9926 * Returns the number of examined objects.
9927 */
9928static int
9929xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9930 xmlXPathStepOpPtr op, xmlNodePtr * first)
9931{
9932 int total = 0, cur;
9933 xmlXPathCompExprPtr comp;
9934 xmlXPathObjectPtr arg1, arg2;
9935
Daniel Veillard556c6682001-10-06 09:59:51 +00009936 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009937 comp = ctxt->comp;
9938 switch (op->op) {
9939 case XPATH_OP_END:
9940 return (0);
9941 case XPATH_OP_UNION:
9942 total =
9943 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9944 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009945 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009946 if ((ctxt->value != NULL)
9947 && (ctxt->value->type == XPATH_NODESET)
9948 && (ctxt->value->nodesetval != NULL)
9949 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9950 /*
9951 * limit tree traversing to first node in the result
9952 */
9953 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9954 *first = ctxt->value->nodesetval->nodeTab[0];
9955 }
9956 cur =
9957 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9958 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009959 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009960 CHECK_TYPE0(XPATH_NODESET);
9961 arg2 = valuePop(ctxt);
9962
9963 CHECK_TYPE0(XPATH_NODESET);
9964 arg1 = valuePop(ctxt);
9965
9966 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9967 arg2->nodesetval);
9968 valuePush(ctxt, arg1);
9969 xmlXPathFreeObject(arg2);
9970 /* optimizer */
9971 if (total > cur)
9972 xmlXPathCompSwap(op);
9973 return (total + cur);
9974 case XPATH_OP_ROOT:
9975 xmlXPathRoot(ctxt);
9976 return (0);
9977 case XPATH_OP_NODE:
9978 if (op->ch1 != -1)
9979 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009980 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009981 if (op->ch2 != -1)
9982 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009983 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009984 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9985 return (total);
9986 case XPATH_OP_RESET:
9987 if (op->ch1 != -1)
9988 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009989 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009990 if (op->ch2 != -1)
9991 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009992 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009993 ctxt->context->node = NULL;
9994 return (total);
9995 case XPATH_OP_COLLECT:{
9996 if (op->ch1 == -1)
9997 return (total);
9998
9999 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010000 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010001
10002 /*
10003 * Optimization for [n] selection where n is a number
10004 */
10005 if ((op->ch2 != -1) &&
10006 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10007 (comp->steps[op->ch2].ch1 == -1) &&
10008 (comp->steps[op->ch2].ch2 != -1) &&
10009 (comp->steps[comp->steps[op->ch2].ch2].op ==
10010 XPATH_OP_VALUE)) {
10011 xmlXPathObjectPtr val;
10012
10013 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10014 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10015 int indx = (int) val->floatval;
10016
10017 if (val->floatval == (float) indx) {
10018 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
10019 first, NULL);
10020 return (total);
10021 }
10022 }
10023 }
10024 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
10025 return (total);
10026 }
10027 case XPATH_OP_VALUE:
10028 valuePush(ctxt,
10029 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10030 return (0);
10031 case XPATH_OP_SORT:
10032 if (op->ch1 != -1)
10033 total +=
10034 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10035 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010036 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010037 if ((ctxt->value != NULL)
10038 && (ctxt->value->type == XPATH_NODESET)
10039 && (ctxt->value->nodesetval != NULL))
10040 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10041 return (total);
10042 default:
10043 return (xmlXPathCompOpEval(ctxt, op));
10044 }
10045}
10046
10047/**
10048 * xmlXPathCompOpEvalLast:
10049 * @ctxt: the XPath parser context with the compiled expression
10050 * @op: an XPath compiled operation
10051 * @last: the last elem found so far
10052 *
10053 * Evaluate the Precompiled XPath operation searching only the last
10054 * element in document order
10055 *
William M. Brack08171912003-12-29 02:52:11 +000010056 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000010057 */
10058static int
10059xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
10060 xmlNodePtr * last)
10061{
10062 int total = 0, cur;
10063 xmlXPathCompExprPtr comp;
10064 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000010065 xmlNodePtr bak;
10066 xmlDocPtr bakd;
10067 int pp;
10068 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010069
Daniel Veillard556c6682001-10-06 09:59:51 +000010070 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010071 comp = ctxt->comp;
10072 switch (op->op) {
10073 case XPATH_OP_END:
10074 return (0);
10075 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000010076 bakd = ctxt->context->doc;
10077 bak = ctxt->context->node;
10078 pp = ctxt->context->proximityPosition;
10079 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010080 total =
10081 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010082 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010083 if ((ctxt->value != NULL)
10084 && (ctxt->value->type == XPATH_NODESET)
10085 && (ctxt->value->nodesetval != NULL)
10086 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10087 /*
10088 * limit tree traversing to first node in the result
10089 */
10090 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10091 *last =
10092 ctxt->value->nodesetval->nodeTab[ctxt->value->
10093 nodesetval->nodeNr -
10094 1];
10095 }
William M. Brackce4fc562004-01-22 02:47:18 +000010096 ctxt->context->doc = bakd;
10097 ctxt->context->node = bak;
10098 ctxt->context->proximityPosition = pp;
10099 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010100 cur =
10101 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010102 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010103 if ((ctxt->value != NULL)
10104 && (ctxt->value->type == XPATH_NODESET)
10105 && (ctxt->value->nodesetval != NULL)
10106 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10107 }
10108 CHECK_TYPE0(XPATH_NODESET);
10109 arg2 = valuePop(ctxt);
10110
10111 CHECK_TYPE0(XPATH_NODESET);
10112 arg1 = valuePop(ctxt);
10113
10114 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10115 arg2->nodesetval);
10116 valuePush(ctxt, arg1);
10117 xmlXPathFreeObject(arg2);
10118 /* optimizer */
10119 if (total > cur)
10120 xmlXPathCompSwap(op);
10121 return (total + cur);
10122 case XPATH_OP_ROOT:
10123 xmlXPathRoot(ctxt);
10124 return (0);
10125 case XPATH_OP_NODE:
10126 if (op->ch1 != -1)
10127 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010128 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010129 if (op->ch2 != -1)
10130 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010131 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010132 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10133 return (total);
10134 case XPATH_OP_RESET:
10135 if (op->ch1 != -1)
10136 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010137 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010138 if (op->ch2 != -1)
10139 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010140 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010141 ctxt->context->node = NULL;
10142 return (total);
10143 case XPATH_OP_COLLECT:{
10144 if (op->ch1 == -1)
10145 return (0);
10146
10147 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010148 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010149
10150 /*
10151 * Optimization for [n] selection where n is a number
10152 */
10153 if ((op->ch2 != -1) &&
10154 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10155 (comp->steps[op->ch2].ch1 == -1) &&
10156 (comp->steps[op->ch2].ch2 != -1) &&
10157 (comp->steps[comp->steps[op->ch2].ch2].op ==
10158 XPATH_OP_VALUE)) {
10159 xmlXPathObjectPtr val;
10160
10161 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10162 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10163 int indx = (int) val->floatval;
10164
10165 if (val->floatval == (float) indx) {
10166 total +=
10167 xmlXPathNodeCollectAndTestNth(ctxt, op,
10168 indx, NULL,
10169 last);
10170 return (total);
10171 }
10172 }
10173 }
10174 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10175 return (total);
10176 }
10177 case XPATH_OP_VALUE:
10178 valuePush(ctxt,
10179 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10180 return (0);
10181 case XPATH_OP_SORT:
10182 if (op->ch1 != -1)
10183 total +=
10184 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10185 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010186 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010187 if ((ctxt->value != NULL)
10188 && (ctxt->value->type == XPATH_NODESET)
10189 && (ctxt->value->nodesetval != NULL))
10190 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10191 return (total);
10192 default:
10193 return (xmlXPathCompOpEval(ctxt, op));
10194 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010195}
10196
Owen Taylor3473f882001-02-23 17:55:21 +000010197/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010198 * xmlXPathCompOpEval:
10199 * @ctxt: the XPath parser context with the compiled expression
10200 * @op: an XPath compiled operation
10201 *
10202 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010203 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010204 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010205static int
10206xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10207{
10208 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010209 int equal, ret;
10210 xmlXPathCompExprPtr comp;
10211 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010212 xmlNodePtr bak;
10213 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010214 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010215 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010216
Daniel Veillard556c6682001-10-06 09:59:51 +000010217 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010218 comp = ctxt->comp;
10219 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010220 case XPATH_OP_END:
10221 return (0);
10222 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010223 bakd = ctxt->context->doc;
10224 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010225 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010226 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010227 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010228 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010229 xmlXPathBooleanFunction(ctxt, 1);
10230 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10231 return (total);
10232 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010233 ctxt->context->doc = bakd;
10234 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010235 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010236 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010237 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010238 if (ctxt->error) {
10239 xmlXPathFreeObject(arg2);
10240 return(0);
10241 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010242 xmlXPathBooleanFunction(ctxt, 1);
10243 arg1 = valuePop(ctxt);
10244 arg1->boolval &= arg2->boolval;
10245 valuePush(ctxt, arg1);
10246 xmlXPathFreeObject(arg2);
10247 return (total);
10248 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010249 bakd = ctxt->context->doc;
10250 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010251 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010252 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010253 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010254 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010255 xmlXPathBooleanFunction(ctxt, 1);
10256 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10257 return (total);
10258 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010259 ctxt->context->doc = bakd;
10260 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010261 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010262 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010263 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010264 if (ctxt->error) {
10265 xmlXPathFreeObject(arg2);
10266 return(0);
10267 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010268 xmlXPathBooleanFunction(ctxt, 1);
10269 arg1 = valuePop(ctxt);
10270 arg1->boolval |= arg2->boolval;
10271 valuePush(ctxt, arg1);
10272 xmlXPathFreeObject(arg2);
10273 return (total);
10274 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010275 bakd = ctxt->context->doc;
10276 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010277 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010278 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010279 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010280 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010281 ctxt->context->doc = bakd;
10282 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010283 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010284 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010285 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010286 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010287 if (op->value)
10288 equal = xmlXPathEqualValues(ctxt);
10289 else
10290 equal = xmlXPathNotEqualValues(ctxt);
10291 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010292 return (total);
10293 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010294 bakd = ctxt->context->doc;
10295 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010296 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010297 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010298 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010299 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010300 ctxt->context->doc = bakd;
10301 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010302 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010303 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010304 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010305 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010306 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10307 valuePush(ctxt, xmlXPathNewBoolean(ret));
10308 return (total);
10309 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010310 bakd = ctxt->context->doc;
10311 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010312 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010313 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010314 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010315 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010316 if (op->ch2 != -1) {
10317 ctxt->context->doc = bakd;
10318 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010319 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010320 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010321 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010322 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010323 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010324 if (op->value == 0)
10325 xmlXPathSubValues(ctxt);
10326 else if (op->value == 1)
10327 xmlXPathAddValues(ctxt);
10328 else if (op->value == 2)
10329 xmlXPathValueFlipSign(ctxt);
10330 else if (op->value == 3) {
10331 CAST_TO_NUMBER;
10332 CHECK_TYPE0(XPATH_NUMBER);
10333 }
10334 return (total);
10335 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010336 bakd = ctxt->context->doc;
10337 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010338 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010339 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010340 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010341 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010342 ctxt->context->doc = bakd;
10343 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010344 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010345 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010346 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 if (op->value == 0)
10349 xmlXPathMultValues(ctxt);
10350 else if (op->value == 1)
10351 xmlXPathDivValues(ctxt);
10352 else if (op->value == 2)
10353 xmlXPathModValues(ctxt);
10354 return (total);
10355 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010356 bakd = ctxt->context->doc;
10357 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010358 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010359 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010360 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010361 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010362 ctxt->context->doc = bakd;
10363 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010364 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010365 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010366 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010367 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010368 CHECK_TYPE0(XPATH_NODESET);
10369 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010370
Daniel Veillardf06307e2001-07-03 10:35:50 +000010371 CHECK_TYPE0(XPATH_NODESET);
10372 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010373
Daniel Veillardf06307e2001-07-03 10:35:50 +000010374 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10375 arg2->nodesetval);
10376 valuePush(ctxt, arg1);
10377 xmlXPathFreeObject(arg2);
10378 return (total);
10379 case XPATH_OP_ROOT:
10380 xmlXPathRoot(ctxt);
10381 return (total);
10382 case XPATH_OP_NODE:
10383 if (op->ch1 != -1)
10384 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010385 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010386 if (op->ch2 != -1)
10387 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010388 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010389 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10390 return (total);
10391 case XPATH_OP_RESET:
10392 if (op->ch1 != -1)
10393 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010394 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010395 if (op->ch2 != -1)
10396 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010397 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010398 ctxt->context->node = NULL;
10399 return (total);
10400 case XPATH_OP_COLLECT:{
10401 if (op->ch1 == -1)
10402 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010403
Daniel Veillardf06307e2001-07-03 10:35:50 +000010404 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010405 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010406
Daniel Veillardf06307e2001-07-03 10:35:50 +000010407 /*
10408 * Optimization for [n] selection where n is a number
10409 */
10410 if ((op->ch2 != -1) &&
10411 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10412 (comp->steps[op->ch2].ch1 == -1) &&
10413 (comp->steps[op->ch2].ch2 != -1) &&
10414 (comp->steps[comp->steps[op->ch2].ch2].op ==
10415 XPATH_OP_VALUE)) {
10416 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010417
Daniel Veillardf06307e2001-07-03 10:35:50 +000010418 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10419 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10420 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010421
Daniel Veillardf06307e2001-07-03 10:35:50 +000010422 if (val->floatval == (float) indx) {
10423 total +=
10424 xmlXPathNodeCollectAndTestNth(ctxt, op,
10425 indx, NULL,
10426 NULL);
10427 return (total);
10428 }
10429 }
10430 }
10431 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10432 return (total);
10433 }
10434 case XPATH_OP_VALUE:
10435 valuePush(ctxt,
10436 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10437 return (total);
10438 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010439 xmlXPathObjectPtr val;
10440
Daniel Veillardf06307e2001-07-03 10:35:50 +000010441 if (op->ch1 != -1)
10442 total +=
10443 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010444 if (op->value5 == NULL) {
10445 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10446 if (val == NULL) {
10447 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10448 return(0);
10449 }
10450 valuePush(ctxt, val);
10451 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010452 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010453
Daniel Veillardf06307e2001-07-03 10:35:50 +000010454 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10455 if (URI == NULL) {
10456 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010457 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010458 op->value4, op->value5);
10459 return (total);
10460 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010461 val = xmlXPathVariableLookupNS(ctxt->context,
10462 op->value4, URI);
10463 if (val == NULL) {
10464 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10465 return(0);
10466 }
10467 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010468 }
10469 return (total);
10470 }
10471 case XPATH_OP_FUNCTION:{
10472 xmlXPathFunction func;
10473 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010474 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010475
10476 if (op->ch1 != -1)
10477 total +=
10478 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010479 if (ctxt->valueNr < op->value) {
10480 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010481 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010482 ctxt->error = XPATH_INVALID_OPERAND;
10483 return (total);
10484 }
10485 for (i = 0; i < op->value; i++)
10486 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10487 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010488 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010489 ctxt->error = XPATH_INVALID_OPERAND;
10490 return (total);
10491 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010492 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000010493 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010494 else {
10495 const xmlChar *URI = NULL;
10496
10497 if (op->value5 == NULL)
10498 func =
10499 xmlXPathFunctionLookup(ctxt->context,
10500 op->value4);
10501 else {
10502 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10503 if (URI == NULL) {
10504 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010505 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010506 op->value4, op->value5);
10507 return (total);
10508 }
10509 func = xmlXPathFunctionLookupNS(ctxt->context,
10510 op->value4, URI);
10511 }
10512 if (func == NULL) {
10513 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010514 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010515 op->value4);
10516 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010517 }
William M. Brackad0e67c2004-12-01 14:35:10 +000010518 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010519 op->cacheURI = (void *) URI;
10520 }
10521 oldFunc = ctxt->context->function;
10522 oldFuncURI = ctxt->context->functionURI;
10523 ctxt->context->function = op->value4;
10524 ctxt->context->functionURI = op->cacheURI;
10525 func(ctxt, op->value);
10526 ctxt->context->function = oldFunc;
10527 ctxt->context->functionURI = oldFuncURI;
10528 return (total);
10529 }
10530 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010531 bakd = ctxt->context->doc;
10532 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000010533 pp = ctxt->context->proximityPosition;
10534 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010535 if (op->ch1 != -1)
10536 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000010537 ctxt->context->contextSize = cs;
10538 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000010539 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000010540 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000010541 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010542 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010543 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010544 ctxt->context->doc = bakd;
10545 ctxt->context->node = bak;
10546 CHECK_ERROR0;
10547 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010548 return (total);
10549 case XPATH_OP_PREDICATE:
10550 case XPATH_OP_FILTER:{
10551 xmlXPathObjectPtr res;
10552 xmlXPathObjectPtr obj, tmp;
10553 xmlNodeSetPtr newset = NULL;
10554 xmlNodeSetPtr oldset;
10555 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000010556 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010557 int i;
10558
10559 /*
10560 * Optimization for ()[1] selection i.e. the first elem
10561 */
10562 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10563 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10564 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10565 xmlXPathObjectPtr val;
10566
10567 val = comp->steps[op->ch2].value4;
10568 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10569 (val->floatval == 1.0)) {
10570 xmlNodePtr first = NULL;
10571
10572 total +=
10573 xmlXPathCompOpEvalFirst(ctxt,
10574 &comp->steps[op->ch1],
10575 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010576 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010577 /*
10578 * The nodeset should be in document order,
10579 * Keep only the first value
10580 */
10581 if ((ctxt->value != NULL) &&
10582 (ctxt->value->type == XPATH_NODESET) &&
10583 (ctxt->value->nodesetval != NULL) &&
10584 (ctxt->value->nodesetval->nodeNr > 1))
10585 ctxt->value->nodesetval->nodeNr = 1;
10586 return (total);
10587 }
10588 }
10589 /*
10590 * Optimization for ()[last()] selection i.e. the last elem
10591 */
10592 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10593 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10594 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10595 int f = comp->steps[op->ch2].ch1;
10596
10597 if ((f != -1) &&
10598 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10599 (comp->steps[f].value5 == NULL) &&
10600 (comp->steps[f].value == 0) &&
10601 (comp->steps[f].value4 != NULL) &&
10602 (xmlStrEqual
10603 (comp->steps[f].value4, BAD_CAST "last"))) {
10604 xmlNodePtr last = NULL;
10605
10606 total +=
10607 xmlXPathCompOpEvalLast(ctxt,
10608 &comp->steps[op->ch1],
10609 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010610 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010611 /*
10612 * The nodeset should be in document order,
10613 * Keep only the last value
10614 */
10615 if ((ctxt->value != NULL) &&
10616 (ctxt->value->type == XPATH_NODESET) &&
10617 (ctxt->value->nodesetval != NULL) &&
10618 (ctxt->value->nodesetval->nodeTab != NULL) &&
10619 (ctxt->value->nodesetval->nodeNr > 1)) {
10620 ctxt->value->nodesetval->nodeTab[0] =
10621 ctxt->value->nodesetval->nodeTab[ctxt->
10622 value->
10623 nodesetval->
10624 nodeNr -
10625 1];
10626 ctxt->value->nodesetval->nodeNr = 1;
10627 }
10628 return (total);
10629 }
10630 }
10631
10632 if (op->ch1 != -1)
10633 total +=
10634 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010635 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010636 if (op->ch2 == -1)
10637 return (total);
10638 if (ctxt->value == NULL)
10639 return (total);
10640
10641 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010642
10643#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010644 /*
10645 * Hum are we filtering the result of an XPointer expression
10646 */
10647 if (ctxt->value->type == XPATH_LOCATIONSET) {
10648 xmlLocationSetPtr newlocset = NULL;
10649 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010650
Daniel Veillardf06307e2001-07-03 10:35:50 +000010651 /*
10652 * Extract the old locset, and then evaluate the result of the
10653 * expression for all the element in the locset. use it to grow
10654 * up a new locset.
10655 */
10656 CHECK_TYPE0(XPATH_LOCATIONSET);
10657 obj = valuePop(ctxt);
10658 oldlocset = obj->user;
10659 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010660
Daniel Veillardf06307e2001-07-03 10:35:50 +000010661 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10662 ctxt->context->contextSize = 0;
10663 ctxt->context->proximityPosition = 0;
10664 if (op->ch2 != -1)
10665 total +=
10666 xmlXPathCompOpEval(ctxt,
10667 &comp->steps[op->ch2]);
10668 res = valuePop(ctxt);
10669 if (res != NULL)
10670 xmlXPathFreeObject(res);
10671 valuePush(ctxt, obj);
10672 CHECK_ERROR0;
10673 return (total);
10674 }
10675 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010676
Daniel Veillardf06307e2001-07-03 10:35:50 +000010677 for (i = 0; i < oldlocset->locNr; i++) {
10678 /*
10679 * Run the evaluation with a node list made of a
10680 * single item in the nodelocset.
10681 */
10682 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010683 ctxt->context->contextSize = oldlocset->locNr;
10684 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010685 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10686 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010687
Daniel Veillardf06307e2001-07-03 10:35:50 +000010688 if (op->ch2 != -1)
10689 total +=
10690 xmlXPathCompOpEval(ctxt,
10691 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010692 if (ctxt->error != XPATH_EXPRESSION_OK) {
10693 xmlXPathFreeObject(obj);
10694 return(0);
10695 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010696
Daniel Veillardf06307e2001-07-03 10:35:50 +000010697 /*
10698 * The result of the evaluation need to be tested to
10699 * decided whether the filter succeeded or not
10700 */
10701 res = valuePop(ctxt);
10702 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10703 xmlXPtrLocationSetAdd(newlocset,
10704 xmlXPathObjectCopy
10705 (oldlocset->locTab[i]));
10706 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010707
Daniel Veillardf06307e2001-07-03 10:35:50 +000010708 /*
10709 * Cleanup
10710 */
10711 if (res != NULL)
10712 xmlXPathFreeObject(res);
10713 if (ctxt->value == tmp) {
10714 res = valuePop(ctxt);
10715 xmlXPathFreeObject(res);
10716 }
10717
10718 ctxt->context->node = NULL;
10719 }
10720
10721 /*
10722 * The result is used as the new evaluation locset.
10723 */
10724 xmlXPathFreeObject(obj);
10725 ctxt->context->node = NULL;
10726 ctxt->context->contextSize = -1;
10727 ctxt->context->proximityPosition = -1;
10728 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10729 ctxt->context->node = oldnode;
10730 return (total);
10731 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010732#endif /* LIBXML_XPTR_ENABLED */
10733
Daniel Veillardf06307e2001-07-03 10:35:50 +000010734 /*
10735 * Extract the old set, and then evaluate the result of the
10736 * expression for all the element in the set. use it to grow
10737 * up a new set.
10738 */
10739 CHECK_TYPE0(XPATH_NODESET);
10740 obj = valuePop(ctxt);
10741 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010742
Daniel Veillardf06307e2001-07-03 10:35:50 +000010743 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000010744 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010745 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010746
Daniel Veillardf06307e2001-07-03 10:35:50 +000010747 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10748 ctxt->context->contextSize = 0;
10749 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000010750/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000010751 if (op->ch2 != -1)
10752 total +=
10753 xmlXPathCompOpEval(ctxt,
10754 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010755 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010756 res = valuePop(ctxt);
10757 if (res != NULL)
10758 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000010759*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000010760 valuePush(ctxt, obj);
10761 ctxt->context->node = oldnode;
10762 CHECK_ERROR0;
10763 } else {
10764 /*
10765 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000010766 * Also set the xpath document in case things like
10767 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000010768 */
10769 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010770
Daniel Veillardf06307e2001-07-03 10:35:50 +000010771 for (i = 0; i < oldset->nodeNr; i++) {
10772 /*
10773 * Run the evaluation with a node list made of
10774 * a single item in the nodeset.
10775 */
10776 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000010777 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
10778 (oldset->nodeTab[i]->doc != NULL))
10779 ctxt->context->doc = oldset->nodeTab[i]->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010780 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10781 valuePush(ctxt, tmp);
10782 ctxt->context->contextSize = oldset->nodeNr;
10783 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010784
Daniel Veillardf06307e2001-07-03 10:35:50 +000010785 if (op->ch2 != -1)
10786 total +=
10787 xmlXPathCompOpEval(ctxt,
10788 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010789 if (ctxt->error != XPATH_EXPRESSION_OK) {
10790 xmlXPathFreeNodeSet(newset);
10791 xmlXPathFreeObject(obj);
10792 return(0);
10793 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010794
Daniel Veillardf06307e2001-07-03 10:35:50 +000010795 /*
William M. Brack08171912003-12-29 02:52:11 +000010796 * The result of the evaluation needs to be tested to
10797 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010798 */
10799 res = valuePop(ctxt);
10800 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10801 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10802 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010803
Daniel Veillardf06307e2001-07-03 10:35:50 +000010804 /*
10805 * Cleanup
10806 */
10807 if (res != NULL)
10808 xmlXPathFreeObject(res);
10809 if (ctxt->value == tmp) {
10810 res = valuePop(ctxt);
10811 xmlXPathFreeObject(res);
10812 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010813
Daniel Veillardf06307e2001-07-03 10:35:50 +000010814 ctxt->context->node = NULL;
10815 }
10816
10817 /*
10818 * The result is used as the new evaluation set.
10819 */
10820 xmlXPathFreeObject(obj);
10821 ctxt->context->node = NULL;
10822 ctxt->context->contextSize = -1;
10823 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000010824 /* may want to move this past the '}' later */
10825 ctxt->context->doc = oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010826 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10827 }
10828 ctxt->context->node = oldnode;
10829 return (total);
10830 }
10831 case XPATH_OP_SORT:
10832 if (op->ch1 != -1)
10833 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010834 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010835 if ((ctxt->value != NULL) &&
10836 (ctxt->value->type == XPATH_NODESET) &&
10837 (ctxt->value->nodesetval != NULL))
10838 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10839 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010840#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010841 case XPATH_OP_RANGETO:{
10842 xmlXPathObjectPtr range;
10843 xmlXPathObjectPtr res, obj;
10844 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010845 xmlLocationSetPtr newlocset = NULL;
10846 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010847 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000010848 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010849
Daniel Veillardf06307e2001-07-03 10:35:50 +000010850 if (op->ch1 != -1)
10851 total +=
10852 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10853 if (op->ch2 == -1)
10854 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010855
William M. Brack08171912003-12-29 02:52:11 +000010856 if (ctxt->value->type == XPATH_LOCATIONSET) {
10857 /*
10858 * Extract the old locset, and then evaluate the result of the
10859 * expression for all the element in the locset. use it to grow
10860 * up a new locset.
10861 */
10862 CHECK_TYPE0(XPATH_LOCATIONSET);
10863 obj = valuePop(ctxt);
10864 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010865
William M. Brack08171912003-12-29 02:52:11 +000010866 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000010867 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000010868 ctxt->context->contextSize = 0;
10869 ctxt->context->proximityPosition = 0;
10870 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10871 res = valuePop(ctxt);
10872 if (res != NULL)
10873 xmlXPathFreeObject(res);
10874 valuePush(ctxt, obj);
10875 CHECK_ERROR0;
10876 return (total);
10877 }
10878 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010879
William M. Brack08171912003-12-29 02:52:11 +000010880 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010881 /*
William M. Brack08171912003-12-29 02:52:11 +000010882 * Run the evaluation with a node list made of a
10883 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010884 */
William M. Brackf7eb7942003-12-31 07:59:17 +000010885 ctxt->context->node = oldlocset->locTab[i]->user;
10886 ctxt->context->contextSize = oldlocset->locNr;
10887 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010888 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10889 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010890
Daniel Veillardf06307e2001-07-03 10:35:50 +000010891 if (op->ch2 != -1)
10892 total +=
10893 xmlXPathCompOpEval(ctxt,
10894 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010895 if (ctxt->error != XPATH_EXPRESSION_OK) {
10896 xmlXPathFreeObject(obj);
10897 return(0);
10898 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010899
Daniel Veillardf06307e2001-07-03 10:35:50 +000010900 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000010901 if (res->type == XPATH_LOCATIONSET) {
10902 xmlLocationSetPtr rloc =
10903 (xmlLocationSetPtr)res->user;
10904 for (j=0; j<rloc->locNr; j++) {
10905 range = xmlXPtrNewRange(
10906 oldlocset->locTab[i]->user,
10907 oldlocset->locTab[i]->index,
10908 rloc->locTab[j]->user2,
10909 rloc->locTab[j]->index2);
10910 if (range != NULL) {
10911 xmlXPtrLocationSetAdd(newlocset, range);
10912 }
10913 }
10914 } else {
10915 range = xmlXPtrNewRangeNodeObject(
10916 (xmlNodePtr)oldlocset->locTab[i]->user, res);
10917 if (range != NULL) {
10918 xmlXPtrLocationSetAdd(newlocset,range);
10919 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010920 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010921
Daniel Veillardf06307e2001-07-03 10:35:50 +000010922 /*
10923 * Cleanup
10924 */
10925 if (res != NULL)
10926 xmlXPathFreeObject(res);
10927 if (ctxt->value == tmp) {
10928 res = valuePop(ctxt);
10929 xmlXPathFreeObject(res);
10930 }
10931
10932 ctxt->context->node = NULL;
10933 }
William M. Brack72ee48d2003-12-30 08:30:19 +000010934 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000010935 CHECK_TYPE0(XPATH_NODESET);
10936 obj = valuePop(ctxt);
10937 oldset = obj->nodesetval;
10938 ctxt->context->node = NULL;
10939
10940 newlocset = xmlXPtrLocationSetCreate(NULL);
10941
10942 if (oldset != NULL) {
10943 for (i = 0; i < oldset->nodeNr; i++) {
10944 /*
10945 * Run the evaluation with a node list made of a single item
10946 * in the nodeset.
10947 */
10948 ctxt->context->node = oldset->nodeTab[i];
10949 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10950 valuePush(ctxt, tmp);
10951
10952 if (op->ch2 != -1)
10953 total +=
10954 xmlXPathCompOpEval(ctxt,
10955 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010956 if (ctxt->error != XPATH_EXPRESSION_OK) {
10957 xmlXPathFreeObject(obj);
10958 return(0);
10959 }
William M. Brack08171912003-12-29 02:52:11 +000010960
William M. Brack08171912003-12-29 02:52:11 +000010961 res = valuePop(ctxt);
10962 range =
10963 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10964 res);
10965 if (range != NULL) {
10966 xmlXPtrLocationSetAdd(newlocset, range);
10967 }
10968
10969 /*
10970 * Cleanup
10971 */
10972 if (res != NULL)
10973 xmlXPathFreeObject(res);
10974 if (ctxt->value == tmp) {
10975 res = valuePop(ctxt);
10976 xmlXPathFreeObject(res);
10977 }
10978
10979 ctxt->context->node = NULL;
10980 }
10981 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010982 }
10983
10984 /*
10985 * The result is used as the new evaluation set.
10986 */
10987 xmlXPathFreeObject(obj);
10988 ctxt->context->node = NULL;
10989 ctxt->context->contextSize = -1;
10990 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010991 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010992 return (total);
10993 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010994#endif /* LIBXML_XPTR_ENABLED */
10995 }
10996 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010997 "XPath: unknown precompiled operation %d\n", op->op);
10998 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010999}
11000
Daniel Veillard56de87e2005-02-16 00:22:29 +000011001#ifdef XPATH_STREAMING
11002/**
11003 * xmlXPathRunStreamEval:
11004 * @ctxt: the XPath parser context with the compiled expression
11005 *
11006 * Evaluate the Precompiled Streamable XPath expression in the given context.
11007 */
11008static xmlXPathObjectPtr
11009xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp) {
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011010 int max_depth, min_depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011011 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011012 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011013#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11014 int eval_all_nodes;
11015#endif
William M. Brack12d37ab2005-02-21 13:54:07 +000011016 xmlNodePtr cur = NULL, limit = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011017 xmlXPathObjectPtr retval;
11018 xmlStreamCtxtPtr patstream;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011019
11020 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011021
11022 if ((ctxt == NULL) || (comp == NULL))
11023 return(NULL);
11024 max_depth = xmlPatternMaxDepth(comp);
11025 if (max_depth == -1)
11026 return(NULL);
11027 if (max_depth == -2)
11028 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011029 min_depth = xmlPatternMinDepth(comp);
11030 if (min_depth == -1)
11031 return(NULL);
Daniel Veillard56de87e2005-02-16 00:22:29 +000011032 from_root = xmlPatternFromRoot(comp);
11033 if (from_root < 0)
11034 return(NULL);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000011035#if 0
11036 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
11037#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011038
11039 retval = xmlXPathNewNodeSet(NULL);
11040 if (retval == NULL)
11041 return(NULL);
11042
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011043 /*
11044 * handle the special cases of / amd . being matched
11045 */
11046 if (min_depth == 0) {
11047 if (from_root) {
11048 xmlXPathNodeSetAddUnique(retval->nodesetval, (xmlNodePtr) ctxt->doc);
11049 } else {
11050 xmlXPathNodeSetAddUnique(retval->nodesetval, ctxt->node);
11051 }
11052 }
11053 if (max_depth == 0) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011054 return(retval);
11055 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011056
Daniel Veillard56de87e2005-02-16 00:22:29 +000011057 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000011058 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011059 } else if (ctxt->node != NULL) {
11060 switch (ctxt->node->type) {
11061 case XML_ELEMENT_NODE:
11062 case XML_DOCUMENT_NODE:
11063 case XML_DOCUMENT_FRAG_NODE:
11064 case XML_HTML_DOCUMENT_NODE:
11065#ifdef LIBXML_DOCB_ENABLED
11066 case XML_DOCB_DOCUMENT_NODE:
11067#endif
11068 cur = ctxt->node;
11069 break;
11070 case XML_ATTRIBUTE_NODE:
11071 case XML_TEXT_NODE:
11072 case XML_CDATA_SECTION_NODE:
11073 case XML_ENTITY_REF_NODE:
11074 case XML_ENTITY_NODE:
11075 case XML_PI_NODE:
11076 case XML_COMMENT_NODE:
11077 case XML_NOTATION_NODE:
11078 case XML_DTD_NODE:
11079 case XML_DOCUMENT_TYPE_NODE:
11080 case XML_ELEMENT_DECL:
11081 case XML_ATTRIBUTE_DECL:
11082 case XML_ENTITY_DECL:
11083 case XML_NAMESPACE_DECL:
11084 case XML_XINCLUDE_START:
11085 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000011086 break;
11087 }
11088 limit = cur;
11089 }
11090 if (cur == NULL)
11091 return(retval);
11092
11093 patstream = xmlPatternGetStreamCtxt(comp);
11094 if (patstream == NULL) {
11095 return(retval);
11096 }
11097
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011098#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11099 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
11100#endif
11101
Daniel Veillard56de87e2005-02-16 00:22:29 +000011102 if (from_root) {
11103 ret = xmlStreamPush(patstream, NULL, NULL);
11104 if (ret < 0) {
11105 } else if (ret == 1) {
11106 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11107 }
11108 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011109 depth = 0;
11110 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011111next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000011112 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011113 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011114
11115 switch (cur->type) {
11116 case XML_ELEMENT_NODE:
11117#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11118 case XML_TEXT_NODE:
11119 case XML_CDATA_SECTION_NODE:
11120 case XML_COMMENT_NODE:
11121 case XML_PI_NODE:
11122#endif
11123 if (cur->type == XML_ELEMENT_NODE) {
11124 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000011125 (cur->ns ? cur->ns->href : NULL));
William M. Brackfbb619f2005-06-06 13:49:18 +000011126 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011127#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11128 else if (eval_all_nodes)
11129 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
11130 else
11131 break;
11132#endif
11133
11134 if (ret < 0) {
11135 /* NOP. */
11136 } else if (ret == 1) {
11137 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11138 }
11139 if ((cur->children == NULL) || (depth >= max_depth)) {
11140 ret = xmlStreamPop(patstream);
11141 while (cur->next != NULL) {
11142 cur = cur->next;
11143 if ((cur->type != XML_ENTITY_DECL) &&
11144 (cur->type != XML_DTD_NODE))
11145 goto next_node;
11146 }
11147 }
11148 default:
11149 break;
11150 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011151
11152scan_children:
11153 if ((cur->children != NULL) && (depth < max_depth)) {
11154 /*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011155 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000011156 */
11157 if (cur->children->type != XML_ENTITY_DECL) {
11158 cur = cur->children;
11159 depth++;
11160 /*
11161 * Skip DTDs
11162 */
11163 if (cur->type != XML_DTD_NODE)
11164 continue;
11165 }
11166 }
11167
11168 if (cur == limit)
11169 break;
11170
11171 while (cur->next != NULL) {
11172 cur = cur->next;
11173 if ((cur->type != XML_ENTITY_DECL) &&
11174 (cur->type != XML_DTD_NODE))
11175 goto next_node;
11176 }
11177
11178 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011179 cur = cur->parent;
11180 depth--;
11181 if ((cur == NULL) || (cur == limit))
11182 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011183 if (cur->type == XML_ELEMENT_NODE) {
11184 ret = xmlStreamPop(patstream);
11185 }
11186#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11187 else if ((eval_all_nodes) &&
11188 ((cur->type == XML_TEXT_NODE) ||
11189 (cur->type == XML_CDATA_SECTION_NODE) ||
11190 (cur->type == XML_COMMENT_NODE) ||
11191 (cur->type == XML_PI_NODE)))
11192 {
11193 ret = xmlStreamPop(patstream);
11194 }
11195#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011196 if (cur->next != NULL) {
11197 cur = cur->next;
11198 break;
11199 }
11200 } while (cur != NULL);
11201
11202 } while ((cur != NULL) && (depth >= 0));
11203done:
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000011204#if 0
11205 printf("stream eval: checked %d nodes selected %d\n",
11206 nb_nodes, retval->nodesetval->nodeNr);
11207#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011208 xmlFreeStreamCtxt(patstream);
11209 return(retval);
11210}
11211#endif /* XPATH_STREAMING */
11212
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011213/**
11214 * xmlXPathRunEval:
11215 * @ctxt: the XPath parser context with the compiled expression
11216 *
11217 * Evaluate the Precompiled XPath expression in the given context.
11218 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011219static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011220xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
11221 xmlXPathCompExprPtr comp;
11222
11223 if ((ctxt == NULL) || (ctxt->comp == NULL))
11224 return;
11225
11226 if (ctxt->valueTab == NULL) {
11227 /* Allocate the value stack */
11228 ctxt->valueTab = (xmlXPathObjectPtr *)
11229 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
11230 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000011231 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011232 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011233 }
11234 ctxt->valueNr = 0;
11235 ctxt->valueMax = 10;
11236 ctxt->value = NULL;
11237 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011238#ifdef XPATH_STREAMING
11239 if (ctxt->comp->stream) {
11240 xmlXPathObjectPtr ret;
11241 ret = xmlXPathRunStreamEval(ctxt->context, ctxt->comp->stream);
11242 if (ret != NULL) {
11243 valuePush(ctxt, ret);
11244 return;
11245 }
11246 }
11247#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011248 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000011249 if(comp->last < 0) {
11250 xmlGenericError(xmlGenericErrorContext,
11251 "xmlXPathRunEval: last is less than zero\n");
11252 return;
11253 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011254 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11255}
11256
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011257/************************************************************************
11258 * *
11259 * Public interfaces *
11260 * *
11261 ************************************************************************/
11262
11263/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011264 * xmlXPathEvalPredicate:
11265 * @ctxt: the XPath context
11266 * @res: the Predicate Expression evaluation result
11267 *
11268 * Evaluate a predicate result for the current node.
11269 * A PredicateExpr is evaluated by evaluating the Expr and converting
11270 * the result to a boolean. If the result is a number, the result will
11271 * be converted to true if the number is equal to the position of the
11272 * context node in the context node list (as returned by the position
11273 * function) and will be converted to false otherwise; if the result
11274 * is not a number, then the result will be converted as if by a call
11275 * to the boolean function.
11276 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011277 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011278 */
11279int
11280xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000011281 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011282 switch (res->type) {
11283 case XPATH_BOOLEAN:
11284 return(res->boolval);
11285 case XPATH_NUMBER:
11286 return(res->floatval == ctxt->proximityPosition);
11287 case XPATH_NODESET:
11288 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011289 if (res->nodesetval == NULL)
11290 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011291 return(res->nodesetval->nodeNr != 0);
11292 case XPATH_STRING:
11293 return((res->stringval != NULL) &&
11294 (xmlStrlen(res->stringval) != 0));
11295 default:
11296 STRANGE
11297 }
11298 return(0);
11299}
11300
11301/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011302 * xmlXPathEvaluatePredicateResult:
11303 * @ctxt: the XPath Parser context
11304 * @res: the Predicate Expression evaluation result
11305 *
11306 * Evaluate a predicate result for the current node.
11307 * A PredicateExpr is evaluated by evaluating the Expr and converting
11308 * the result to a boolean. If the result is a number, the result will
11309 * be converted to true if the number is equal to the position of the
11310 * context node in the context node list (as returned by the position
11311 * function) and will be converted to false otherwise; if the result
11312 * is not a number, then the result will be converted as if by a call
11313 * to the boolean function.
11314 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011315 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011316 */
11317int
11318xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
11319 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000011320 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011321 switch (res->type) {
11322 case XPATH_BOOLEAN:
11323 return(res->boolval);
11324 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000011325#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000011326 return((res->floatval == ctxt->context->proximityPosition) &&
11327 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000011328#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011329 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000011330#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011331 case XPATH_NODESET:
11332 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000011333 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000011334 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011335 return(res->nodesetval->nodeNr != 0);
11336 case XPATH_STRING:
11337 return((res->stringval != NULL) &&
11338 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000011339#ifdef LIBXML_XPTR_ENABLED
11340 case XPATH_LOCATIONSET:{
11341 xmlLocationSetPtr ptr = res->user;
11342 if (ptr == NULL)
11343 return(0);
11344 return (ptr->locNr != 0);
11345 }
11346#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011347 default:
11348 STRANGE
11349 }
11350 return(0);
11351}
11352
Daniel Veillard56de87e2005-02-16 00:22:29 +000011353#ifdef XPATH_STREAMING
11354/**
11355 * xmlXPathTryStreamCompile:
11356 * @ctxt: an XPath context
11357 * @str: the XPath expression
11358 *
11359 * Try to compile the XPath expression as a streamable subset.
11360 *
11361 * Returns the compiled expression or NULL if failed to compile.
11362 */
11363static xmlXPathCompExprPtr
11364xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11365 /*
11366 * Optimization: use streaming patterns when the XPath expression can
11367 * be compiled to a stream lookup
11368 */
11369 xmlPatternPtr stream;
11370 xmlXPathCompExprPtr comp;
11371 xmlDictPtr dict = NULL;
11372 const xmlChar **namespaces = NULL;
11373 xmlNsPtr ns;
11374 int i, j;
11375
11376 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
11377 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000011378 const xmlChar *tmp;
11379
11380 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000011381 * We don't try to handle expressions using the verbose axis
11382 * specifiers ("::"), just the simplied form at this point.
11383 * Additionally, if there is no list of namespaces available and
11384 * there's a ":" in the expression, indicating a prefixed QName,
11385 * then we won't try to compile either. xmlPatterncompile() needs
11386 * to have a list of namespaces at compilation time in order to
11387 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000011388 */
11389 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000011390 if ((tmp != NULL) &&
11391 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
11392 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000011393
Daniel Veillard56de87e2005-02-16 00:22:29 +000011394 if (ctxt != NULL) {
11395 dict = ctxt->dict;
11396 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000011397 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000011398 if (namespaces == NULL) {
11399 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
11400 return(NULL);
11401 }
11402 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
11403 ns = ctxt->namespaces[j];
11404 namespaces[i++] = ns->href;
11405 namespaces[i++] = ns->prefix;
11406 }
11407 namespaces[i++] = NULL;
11408 namespaces[i++] = NULL;
11409 }
11410 }
11411
William M. Brackea152c02005-06-09 18:12:28 +000011412 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
11413 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000011414 if (namespaces != NULL) {
11415 xmlFree((xmlChar **)namespaces);
11416 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011417 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
11418 comp = xmlXPathNewCompExpr();
11419 if (comp == NULL) {
11420 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
11421 return(NULL);
11422 }
11423 comp->stream = stream;
11424 comp->dict = dict;
11425 if (comp->dict)
11426 xmlDictReference(comp->dict);
11427 return(comp);
11428 }
11429 xmlFreePattern(stream);
11430 }
11431 return(NULL);
11432}
11433#endif /* XPATH_STREAMING */
11434
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011435/**
Daniel Veillard4773df22004-01-23 13:15:13 +000011436 * xmlXPathCtxtCompile:
11437 * @ctxt: an XPath context
11438 * @str: the XPath expression
11439 *
11440 * Compile an XPath expression
11441 *
11442 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
11443 * the caller has to free the object.
11444 */
11445xmlXPathCompExprPtr
11446xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11447 xmlXPathParserContextPtr pctxt;
11448 xmlXPathCompExprPtr comp;
11449
Daniel Veillard56de87e2005-02-16 00:22:29 +000011450#ifdef XPATH_STREAMING
11451 comp = xmlXPathTryStreamCompile(ctxt, str);
11452 if (comp != NULL)
11453 return(comp);
11454#endif
11455
Daniel Veillard4773df22004-01-23 13:15:13 +000011456 xmlXPathInit();
11457
11458 pctxt = xmlXPathNewParserContext(str, ctxt);
11459 xmlXPathCompileExpr(pctxt);
11460
11461 if( pctxt->error != XPATH_EXPRESSION_OK )
11462 {
11463 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011464 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000011465 }
11466
11467 if (*pctxt->cur != 0) {
11468 /*
11469 * aleksey: in some cases this line prints *second* error message
11470 * (see bug #78858) and probably this should be fixed.
11471 * However, we are not sure that all error messages are printed
11472 * out in other places. It's not critical so we leave it as-is for now
11473 */
11474 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11475 comp = NULL;
11476 } else {
11477 comp = pctxt->comp;
11478 pctxt->comp = NULL;
11479 }
11480 xmlXPathFreeParserContext(pctxt);
11481 if (comp != NULL) {
11482 comp->expr = xmlStrdup(str);
11483#ifdef DEBUG_EVAL_COUNTS
11484 comp->string = xmlStrdup(str);
11485 comp->nb = 0;
11486#endif
11487 }
11488 return(comp);
11489}
11490
11491/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011492 * xmlXPathCompile:
11493 * @str: the XPath expression
11494 *
11495 * Compile an XPath expression
11496 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000011497 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011498 * the caller has to free the object.
11499 */
11500xmlXPathCompExprPtr
11501xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000011502 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011503}
11504
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011505/**
11506 * xmlXPathCompiledEval:
11507 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000011508 * @ctx: the XPath context
11509 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011510 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000011511 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011512 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000011513 * the caller has to free the object.
11514 */
11515xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011516xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000011517 xmlXPathParserContextPtr ctxt;
11518 xmlXPathObjectPtr res, tmp, init = NULL;
11519 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000011520#ifndef LIBXML_THREAD_ENABLED
11521 static int reentance = 0;
11522#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011523
William M. Brackf13f77f2004-11-12 16:03:48 +000011524 CHECK_CTXT(ctx)
11525
11526 if (comp == NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011527 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011528 xmlXPathInit();
11529
Daniel Veillard81463942001-10-16 12:34:39 +000011530#ifndef LIBXML_THREAD_ENABLED
11531 reentance++;
11532 if (reentance > 1)
11533 xmlXPathDisableOptimizer = 1;
11534#endif
11535
Daniel Veillardf06307e2001-07-03 10:35:50 +000011536#ifdef DEBUG_EVAL_COUNTS
11537 comp->nb++;
11538 if ((comp->string != NULL) && (comp->nb > 100)) {
11539 fprintf(stderr, "100 x %s\n", comp->string);
11540 comp->nb = 0;
11541 }
11542#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011543 ctxt = xmlXPathCompParserContext(comp, ctx);
11544 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011545
11546 if (ctxt->value == NULL) {
11547 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011548 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011549 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011550 } else {
11551 res = valuePop(ctxt);
11552 }
11553
Daniel Veillardf06307e2001-07-03 10:35:50 +000011554
Owen Taylor3473f882001-02-23 17:55:21 +000011555 do {
11556 tmp = valuePop(ctxt);
11557 if (tmp != NULL) {
11558 if (tmp != init)
11559 stack++;
11560 xmlXPathFreeObject(tmp);
11561 }
11562 } while (tmp != NULL);
11563 if ((stack != 0) && (res != NULL)) {
11564 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011565 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011566 stack);
11567 }
11568 if (ctxt->error != XPATH_EXPRESSION_OK) {
11569 xmlXPathFreeObject(res);
11570 res = NULL;
11571 }
11572
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011573
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011574 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011575 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011576#ifndef LIBXML_THREAD_ENABLED
11577 reentance--;
11578#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011579 return(res);
11580}
11581
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011582/**
11583 * xmlXPathEvalExpr:
11584 * @ctxt: the XPath Parser context
11585 *
11586 * Parse and evaluate an XPath expression in the given context,
11587 * then push the result on the context stack
11588 */
11589void
11590xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011591#ifdef XPATH_STREAMING
11592 xmlXPathCompExprPtr comp;
11593#endif
11594
Daniel Veillarda82b1822004-11-08 16:24:57 +000011595 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011596
11597#ifdef XPATH_STREAMING
11598 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
11599 if (comp != NULL) {
11600 if (ctxt->comp != NULL)
11601 xmlXPathFreeCompExpr(ctxt->comp);
11602 ctxt->comp = comp;
11603 if (ctxt->cur != NULL)
11604 while (*ctxt->cur != 0) ctxt->cur++;
11605 } else
11606#endif
11607 {
11608 xmlXPathCompileExpr(ctxt);
11609 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011610 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011611 xmlXPathRunEval(ctxt);
11612}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011613
11614/**
11615 * xmlXPathEval:
11616 * @str: the XPath expression
11617 * @ctx: the XPath context
11618 *
11619 * Evaluate the XPath Location Path in the given context.
11620 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011621 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011622 * the caller has to free the object.
11623 */
11624xmlXPathObjectPtr
11625xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11626 xmlXPathParserContextPtr ctxt;
11627 xmlXPathObjectPtr res, tmp, init = NULL;
11628 int stack = 0;
11629
William M. Brackf13f77f2004-11-12 16:03:48 +000011630 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011631
William M. Brackf13f77f2004-11-12 16:03:48 +000011632 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011633
11634 ctxt = xmlXPathNewParserContext(str, ctx);
11635 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011636
11637 if (ctxt->value == NULL) {
11638 xmlGenericError(xmlGenericErrorContext,
11639 "xmlXPathEval: evaluation failed\n");
11640 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011641 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
11642#ifdef XPATH_STREAMING
11643 && (ctxt->comp->stream == NULL)
11644#endif
11645 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011646 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11647 res = NULL;
11648 } else {
11649 res = valuePop(ctxt);
11650 }
11651
11652 do {
11653 tmp = valuePop(ctxt);
11654 if (tmp != NULL) {
11655 if (tmp != init)
11656 stack++;
11657 xmlXPathFreeObject(tmp);
11658 }
11659 } while (tmp != NULL);
11660 if ((stack != 0) && (res != NULL)) {
11661 xmlGenericError(xmlGenericErrorContext,
11662 "xmlXPathEval: %d object left on the stack\n",
11663 stack);
11664 }
11665 if (ctxt->error != XPATH_EXPRESSION_OK) {
11666 xmlXPathFreeObject(res);
11667 res = NULL;
11668 }
11669
Owen Taylor3473f882001-02-23 17:55:21 +000011670 xmlXPathFreeParserContext(ctxt);
11671 return(res);
11672}
11673
11674/**
11675 * xmlXPathEvalExpression:
11676 * @str: the XPath expression
11677 * @ctxt: the XPath context
11678 *
11679 * Evaluate the XPath expression in the given context.
11680 *
11681 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11682 * the caller has to free the object.
11683 */
11684xmlXPathObjectPtr
11685xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11686 xmlXPathParserContextPtr pctxt;
11687 xmlXPathObjectPtr res, tmp;
11688 int stack = 0;
11689
William M. Brackf13f77f2004-11-12 16:03:48 +000011690 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000011691
William M. Brackf13f77f2004-11-12 16:03:48 +000011692 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000011693
11694 pctxt = xmlXPathNewParserContext(str, ctxt);
11695 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011696
11697 if (*pctxt->cur != 0) {
11698 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11699 res = NULL;
11700 } else {
11701 res = valuePop(pctxt);
11702 }
11703 do {
11704 tmp = valuePop(pctxt);
11705 if (tmp != NULL) {
11706 xmlXPathFreeObject(tmp);
11707 stack++;
11708 }
11709 } while (tmp != NULL);
11710 if ((stack != 0) && (res != NULL)) {
11711 xmlGenericError(xmlGenericErrorContext,
11712 "xmlXPathEvalExpression: %d object left on the stack\n",
11713 stack);
11714 }
11715 xmlXPathFreeParserContext(pctxt);
11716 return(res);
11717}
11718
Daniel Veillard42766c02002-08-22 20:52:17 +000011719/************************************************************************
11720 * *
11721 * Extra functions not pertaining to the XPath spec *
11722 * *
11723 ************************************************************************/
11724/**
11725 * xmlXPathEscapeUriFunction:
11726 * @ctxt: the XPath Parser context
11727 * @nargs: the number of arguments
11728 *
11729 * Implement the escape-uri() XPath function
11730 * string escape-uri(string $str, bool $escape-reserved)
11731 *
11732 * This function applies the URI escaping rules defined in section 2 of [RFC
11733 * 2396] to the string supplied as $uri-part, which typically represents all
11734 * or part of a URI. The effect of the function is to replace any special
11735 * character in the string by an escape sequence of the form %xx%yy...,
11736 * where xxyy... is the hexadecimal representation of the octets used to
11737 * represent the character in UTF-8.
11738 *
11739 * The set of characters that are escaped depends on the setting of the
11740 * boolean argument $escape-reserved.
11741 *
11742 * If $escape-reserved is true, all characters are escaped other than lower
11743 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11744 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11745 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11746 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11747 * A-F).
11748 *
11749 * If $escape-reserved is false, the behavior differs in that characters
11750 * referred to in [RFC 2396] as reserved characters are not escaped. These
11751 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11752 *
11753 * [RFC 2396] does not define whether escaped URIs should use lower case or
11754 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11755 * compared using string comparison functions, this function must always use
11756 * the upper-case letters A-F.
11757 *
11758 * Generally, $escape-reserved should be set to true when escaping a string
11759 * that is to form a single part of a URI, and to false when escaping an
11760 * entire URI or URI reference.
11761 *
11762 * In the case of non-ascii characters, the string is encoded according to
11763 * utf-8 and then converted according to RFC 2396.
11764 *
11765 * Examples
11766 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11767 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11768 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11769 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11770 *
11771 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011772static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011773xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11774 xmlXPathObjectPtr str;
11775 int escape_reserved;
11776 xmlBufferPtr target;
11777 xmlChar *cptr;
11778 xmlChar escape[4];
11779
11780 CHECK_ARITY(2);
11781
11782 escape_reserved = xmlXPathPopBoolean(ctxt);
11783
11784 CAST_TO_STRING;
11785 str = valuePop(ctxt);
11786
11787 target = xmlBufferCreate();
11788
11789 escape[0] = '%';
11790 escape[3] = 0;
11791
11792 if (target) {
11793 for (cptr = str->stringval; *cptr; cptr++) {
11794 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11795 (*cptr >= 'a' && *cptr <= 'z') ||
11796 (*cptr >= '0' && *cptr <= '9') ||
11797 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11798 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11799 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11800 (*cptr == '%' &&
11801 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11802 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11803 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11804 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11805 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11806 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11807 (!escape_reserved &&
11808 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11809 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11810 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11811 *cptr == ','))) {
11812 xmlBufferAdd(target, cptr, 1);
11813 } else {
11814 if ((*cptr >> 4) < 10)
11815 escape[1] = '0' + (*cptr >> 4);
11816 else
11817 escape[1] = 'A' - 10 + (*cptr >> 4);
11818 if ((*cptr & 0xF) < 10)
11819 escape[2] = '0' + (*cptr & 0xF);
11820 else
11821 escape[2] = 'A' - 10 + (*cptr & 0xF);
11822
11823 xmlBufferAdd(target, &escape[0], 3);
11824 }
11825 }
11826 }
11827 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11828 xmlBufferFree(target);
11829 xmlXPathFreeObject(str);
11830}
11831
Owen Taylor3473f882001-02-23 17:55:21 +000011832/**
11833 * xmlXPathRegisterAllFunctions:
11834 * @ctxt: the XPath context
11835 *
11836 * Registers all default XPath functions in this context
11837 */
11838void
11839xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11840{
11841 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11842 xmlXPathBooleanFunction);
11843 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11844 xmlXPathCeilingFunction);
11845 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11846 xmlXPathCountFunction);
11847 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11848 xmlXPathConcatFunction);
11849 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11850 xmlXPathContainsFunction);
11851 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11852 xmlXPathIdFunction);
11853 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11854 xmlXPathFalseFunction);
11855 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11856 xmlXPathFloorFunction);
11857 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11858 xmlXPathLastFunction);
11859 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11860 xmlXPathLangFunction);
11861 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11862 xmlXPathLocalNameFunction);
11863 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11864 xmlXPathNotFunction);
11865 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11866 xmlXPathNameFunction);
11867 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11868 xmlXPathNamespaceURIFunction);
11869 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11870 xmlXPathNormalizeFunction);
11871 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11872 xmlXPathNumberFunction);
11873 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11874 xmlXPathPositionFunction);
11875 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11876 xmlXPathRoundFunction);
11877 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11878 xmlXPathStringFunction);
11879 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11880 xmlXPathStringLengthFunction);
11881 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11882 xmlXPathStartsWithFunction);
11883 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11884 xmlXPathSubstringFunction);
11885 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11886 xmlXPathSubstringBeforeFunction);
11887 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11888 xmlXPathSubstringAfterFunction);
11889 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11890 xmlXPathSumFunction);
11891 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11892 xmlXPathTrueFunction);
11893 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11894 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011895
11896 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11897 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11898 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011899}
11900
11901#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000011902#define bottom_xpath
11903#include "elfgcchack.h"