blob: f01b94dcdca235176023360cd93a3940f2d24fd9 [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{
295 ctxt->error = XPATH_MEMORY_ERROR;
296 if (ctxt == NULL)
297 xmlXPathErrMemory(NULL, extra);
298 else
299 xmlXPathErrMemory(ctxt->context, extra);
300}
301
302/**
303 * xmlXPathErr:
304 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000305 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000306 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000307 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000308 */
309void
310xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
311{
William M. Brackcd65bc92005-01-06 09:39:18 +0000312 if ((error < 0) || (error > MAXERRNO))
313 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000314 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000315 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000316 NULL, NULL, XML_FROM_XPATH,
317 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
318 XML_ERR_ERROR, NULL, 0,
319 NULL, NULL, NULL, 0, 0,
320 xmlXPathErrorMessages[error]);
321 return;
322 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000323 ctxt->error = error;
324 if (ctxt->context == NULL) {
325 __xmlRaiseError(NULL, NULL, NULL,
326 NULL, NULL, XML_FROM_XPATH,
327 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
328 XML_ERR_ERROR, NULL, 0,
329 (const char *) ctxt->base, NULL, NULL,
330 ctxt->cur - ctxt->base, 0,
331 xmlXPathErrorMessages[error]);
332 return;
333 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000334 ctxt->context->lastError.domain = XML_FROM_XPATH;
335 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
336 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000337 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000338 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
339 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
340 ctxt->context->lastError.node = ctxt->context->debugNode;
341 if (ctxt->context->error != NULL) {
342 ctxt->context->error(ctxt->context->userData,
343 &ctxt->context->lastError);
344 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000345 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000346 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
347 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
348 XML_ERR_ERROR, NULL, 0,
349 (const char *) ctxt->base, NULL, NULL,
350 ctxt->cur - ctxt->base, 0,
351 xmlXPathErrorMessages[error]);
352 }
353
354}
355
356/**
357 * xmlXPatherror:
358 * @ctxt: the XPath Parser context
359 * @file: the file name
360 * @line: the line number
361 * @no: the error number
362 *
363 * Formats an error message.
364 */
365void
366xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
367 int line ATTRIBUTE_UNUSED, int no) {
368 xmlXPathErr(ctxt, no);
369}
370
371
372/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000373 * *
374 * Parser Types *
375 * *
376 ************************************************************************/
377
378/*
379 * Types are private:
380 */
381
382typedef enum {
383 XPATH_OP_END=0,
384 XPATH_OP_AND,
385 XPATH_OP_OR,
386 XPATH_OP_EQUAL,
387 XPATH_OP_CMP,
388 XPATH_OP_PLUS,
389 XPATH_OP_MULT,
390 XPATH_OP_UNION,
391 XPATH_OP_ROOT,
392 XPATH_OP_NODE,
393 XPATH_OP_RESET,
394 XPATH_OP_COLLECT,
395 XPATH_OP_VALUE,
396 XPATH_OP_VARIABLE,
397 XPATH_OP_FUNCTION,
398 XPATH_OP_ARG,
399 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000400 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000401 XPATH_OP_SORT
402#ifdef LIBXML_XPTR_ENABLED
403 ,XPATH_OP_RANGETO
404#endif
405} xmlXPathOp;
406
407typedef enum {
408 AXIS_ANCESTOR = 1,
409 AXIS_ANCESTOR_OR_SELF,
410 AXIS_ATTRIBUTE,
411 AXIS_CHILD,
412 AXIS_DESCENDANT,
413 AXIS_DESCENDANT_OR_SELF,
414 AXIS_FOLLOWING,
415 AXIS_FOLLOWING_SIBLING,
416 AXIS_NAMESPACE,
417 AXIS_PARENT,
418 AXIS_PRECEDING,
419 AXIS_PRECEDING_SIBLING,
420 AXIS_SELF
421} xmlXPathAxisVal;
422
423typedef enum {
424 NODE_TEST_NONE = 0,
425 NODE_TEST_TYPE = 1,
426 NODE_TEST_PI = 2,
427 NODE_TEST_ALL = 3,
428 NODE_TEST_NS = 4,
429 NODE_TEST_NAME = 5
430} xmlXPathTestVal;
431
432typedef enum {
433 NODE_TYPE_NODE = 0,
434 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
435 NODE_TYPE_TEXT = XML_TEXT_NODE,
436 NODE_TYPE_PI = XML_PI_NODE
437} xmlXPathTypeVal;
438
439
440typedef struct _xmlXPathStepOp xmlXPathStepOp;
441typedef xmlXPathStepOp *xmlXPathStepOpPtr;
442struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000443 xmlXPathOp op; /* The identifier of the operation */
444 int ch1; /* First child */
445 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000446 int value;
447 int value2;
448 int value3;
449 void *value4;
450 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000451 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000452 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000453};
454
455struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000456 int nbStep; /* Number of steps in this expression */
457 int maxStep; /* Maximum number of steps allocated */
458 xmlXPathStepOp *steps; /* ops for computation of this expression */
459 int last; /* index of last step in expression */
460 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000461 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000462#ifdef DEBUG_EVAL_COUNTS
463 int nb;
464 xmlChar *string;
465#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000466#ifdef XPATH_STREAMING
467 xmlPatternPtr stream;
468#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000469};
470
471/************************************************************************
472 * *
473 * Parser Type functions *
474 * *
475 ************************************************************************/
476
477/**
478 * xmlXPathNewCompExpr:
479 *
480 * Create a new Xpath component
481 *
482 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
483 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000484static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000485xmlXPathNewCompExpr(void) {
486 xmlXPathCompExprPtr cur;
487
488 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
489 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000490 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000491 return(NULL);
492 }
493 memset(cur, 0, sizeof(xmlXPathCompExpr));
494 cur->maxStep = 10;
495 cur->nbStep = 0;
496 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
497 sizeof(xmlXPathStepOp));
498 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000499 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000500 xmlFree(cur);
501 return(NULL);
502 }
503 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
504 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000505#ifdef DEBUG_EVAL_COUNTS
506 cur->nb = 0;
507#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000508 return(cur);
509}
510
511/**
512 * xmlXPathFreeCompExpr:
513 * @comp: an XPATH comp
514 *
515 * Free up the memory allocated by @comp
516 */
517void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000518xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
519{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000520 xmlXPathStepOpPtr op;
521 int i;
522
523 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000524 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000525 if (comp->dict == NULL) {
526 for (i = 0; i < comp->nbStep; i++) {
527 op = &comp->steps[i];
528 if (op->value4 != NULL) {
529 if (op->op == XPATH_OP_VALUE)
530 xmlXPathFreeObject(op->value4);
531 else
532 xmlFree(op->value4);
533 }
534 if (op->value5 != NULL)
535 xmlFree(op->value5);
536 }
537 } else {
538 for (i = 0; i < comp->nbStep; i++) {
539 op = &comp->steps[i];
540 if (op->value4 != NULL) {
541 if (op->op == XPATH_OP_VALUE)
542 xmlXPathFreeObject(op->value4);
543 }
544 }
545 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000546 }
547 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000548 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000549 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000550#ifdef DEBUG_EVAL_COUNTS
551 if (comp->string != NULL) {
552 xmlFree(comp->string);
553 }
554#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000555#ifdef XPATH_STREAMING
556 if (comp->stream != NULL) {
557 xmlFreePatternList(comp->stream);
558 }
559#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000560 if (comp->expr != NULL) {
561 xmlFree(comp->expr);
562 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000563
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000564 xmlFree(comp);
565}
566
567/**
568 * xmlXPathCompExprAdd:
569 * @comp: the compiled expression
570 * @ch1: first child index
571 * @ch2: second child index
572 * @op: an op
573 * @value: the first int value
574 * @value2: the second int value
575 * @value3: the third int value
576 * @value4: the first string value
577 * @value5: the second string value
578 *
William M. Brack08171912003-12-29 02:52:11 +0000579 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000580 *
581 * Returns -1 in case of failure, the index otherwise
582 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000583static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000584xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
585 xmlXPathOp op, int value,
586 int value2, int value3, void *value4, void *value5) {
587 if (comp->nbStep >= comp->maxStep) {
588 xmlXPathStepOp *real;
589
590 comp->maxStep *= 2;
591 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
592 comp->maxStep * sizeof(xmlXPathStepOp));
593 if (real == NULL) {
594 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000595 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000596 return(-1);
597 }
598 comp->steps = real;
599 }
600 comp->last = comp->nbStep;
601 comp->steps[comp->nbStep].ch1 = ch1;
602 comp->steps[comp->nbStep].ch2 = ch2;
603 comp->steps[comp->nbStep].op = op;
604 comp->steps[comp->nbStep].value = value;
605 comp->steps[comp->nbStep].value2 = value2;
606 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000607 if ((comp->dict != NULL) &&
608 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
609 (op == XPATH_OP_COLLECT))) {
610 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000611 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000612 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000613 xmlFree(value4);
614 } else
615 comp->steps[comp->nbStep].value4 = NULL;
616 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000617 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000618 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000619 xmlFree(value5);
620 } else
621 comp->steps[comp->nbStep].value5 = NULL;
622 } else {
623 comp->steps[comp->nbStep].value4 = value4;
624 comp->steps[comp->nbStep].value5 = value5;
625 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000626 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000627 return(comp->nbStep++);
628}
629
Daniel Veillardf06307e2001-07-03 10:35:50 +0000630/**
631 * xmlXPathCompSwap:
632 * @comp: the compiled expression
633 * @op: operation index
634 *
635 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000636 */
637static void
638xmlXPathCompSwap(xmlXPathStepOpPtr op) {
639 int tmp;
640
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000641#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000642 /*
643 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000644 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000645 * application
646 */
647 if (xmlXPathDisableOptimizer)
648 return;
649#endif
650
Daniel Veillardf06307e2001-07-03 10:35:50 +0000651 tmp = op->ch1;
652 op->ch1 = op->ch2;
653 op->ch2 = tmp;
654}
655
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000656#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
657 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
658 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000659#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
660 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
661 (op), (val), (val2), (val3), (val4), (val5))
662
663#define PUSH_LEAVE_EXPR(op, val, val2) \
664xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
665
666#define PUSH_UNARY_EXPR(op, ch, val, val2) \
667xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
668
669#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000670xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
671 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000672
673/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000674 * *
675 * Debugging related functions *
676 * *
677 ************************************************************************/
678
Owen Taylor3473f882001-02-23 17:55:21 +0000679#define STRANGE \
680 xmlGenericError(xmlGenericErrorContext, \
681 "Internal error at %s:%d\n", \
682 __FILE__, __LINE__);
683
684#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000685static void
686xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000687 int i;
688 char shift[100];
689
690 for (i = 0;((i < depth) && (i < 25));i++)
691 shift[2 * i] = shift[2 * i + 1] = ' ';
692 shift[2 * i] = shift[2 * i + 1] = 0;
693 if (cur == NULL) {
694 fprintf(output, shift);
695 fprintf(output, "Node is NULL !\n");
696 return;
697
698 }
699
700 if ((cur->type == XML_DOCUMENT_NODE) ||
701 (cur->type == XML_HTML_DOCUMENT_NODE)) {
702 fprintf(output, shift);
703 fprintf(output, " /\n");
704 } else if (cur->type == XML_ATTRIBUTE_NODE)
705 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
706 else
707 xmlDebugDumpOneNode(output, cur, depth);
708}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000709static void
710xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000711 xmlNodePtr tmp;
712 int i;
713 char shift[100];
714
715 for (i = 0;((i < depth) && (i < 25));i++)
716 shift[2 * i] = shift[2 * i + 1] = ' ';
717 shift[2 * i] = shift[2 * i + 1] = 0;
718 if (cur == NULL) {
719 fprintf(output, shift);
720 fprintf(output, "Node is NULL !\n");
721 return;
722
723 }
724
725 while (cur != NULL) {
726 tmp = cur;
727 cur = cur->next;
728 xmlDebugDumpOneNode(output, tmp, depth);
729 }
730}
Owen Taylor3473f882001-02-23 17:55:21 +0000731
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000732static void
733xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000734 int i;
735 char shift[100];
736
737 for (i = 0;((i < depth) && (i < 25));i++)
738 shift[2 * i] = shift[2 * i + 1] = ' ';
739 shift[2 * i] = shift[2 * i + 1] = 0;
740
741 if (cur == NULL) {
742 fprintf(output, shift);
743 fprintf(output, "NodeSet is NULL !\n");
744 return;
745
746 }
747
Daniel Veillard911f49a2001-04-07 15:39:35 +0000748 if (cur != NULL) {
749 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
750 for (i = 0;i < cur->nodeNr;i++) {
751 fprintf(output, shift);
752 fprintf(output, "%d", i + 1);
753 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
754 }
Owen Taylor3473f882001-02-23 17:55:21 +0000755 }
756}
757
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000758static void
759xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000760 int i;
761 char shift[100];
762
763 for (i = 0;((i < depth) && (i < 25));i++)
764 shift[2 * i] = shift[2 * i + 1] = ' ';
765 shift[2 * i] = shift[2 * i + 1] = 0;
766
767 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
768 fprintf(output, shift);
769 fprintf(output, "Value Tree is NULL !\n");
770 return;
771
772 }
773
774 fprintf(output, shift);
775 fprintf(output, "%d", i + 1);
776 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
777}
Owen Taylor3473f882001-02-23 17:55:21 +0000778#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000779static void
780xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000781 int i;
782 char shift[100];
783
784 for (i = 0;((i < depth) && (i < 25));i++)
785 shift[2 * i] = shift[2 * i + 1] = ' ';
786 shift[2 * i] = shift[2 * i + 1] = 0;
787
788 if (cur == NULL) {
789 fprintf(output, shift);
790 fprintf(output, "LocationSet is NULL !\n");
791 return;
792
793 }
794
795 for (i = 0;i < cur->locNr;i++) {
796 fprintf(output, shift);
797 fprintf(output, "%d : ", i + 1);
798 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
799 }
800}
Daniel Veillard017b1082001-06-21 11:20:21 +0000801#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000802
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000803/**
804 * xmlXPathDebugDumpObject:
805 * @output: the FILE * to dump the output
806 * @cur: the object to inspect
807 * @depth: indentation level
808 *
809 * Dump the content of the object for debugging purposes
810 */
811void
812xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000813 int i;
814 char shift[100];
815
Daniel Veillarda82b1822004-11-08 16:24:57 +0000816 if (output == NULL) return;
817
Owen Taylor3473f882001-02-23 17:55:21 +0000818 for (i = 0;((i < depth) && (i < 25));i++)
819 shift[2 * i] = shift[2 * i + 1] = ' ';
820 shift[2 * i] = shift[2 * i + 1] = 0;
821
Kasimier T. Buchcik97258712006-01-05 12:30:43 +0000822
823 fprintf(output, shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000824
825 if (cur == NULL) {
826 fprintf(output, "Object is empty (NULL)\n");
827 return;
828 }
829 switch(cur->type) {
830 case XPATH_UNDEFINED:
831 fprintf(output, "Object is uninitialized\n");
832 break;
833 case XPATH_NODESET:
834 fprintf(output, "Object is a Node Set :\n");
835 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
836 break;
837 case XPATH_XSLT_TREE:
838 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000839 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000840 break;
841 case XPATH_BOOLEAN:
842 fprintf(output, "Object is a Boolean : ");
843 if (cur->boolval) fprintf(output, "true\n");
844 else fprintf(output, "false\n");
845 break;
846 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000847 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000848 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000849 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000850 break;
851 case -1:
852 fprintf(output, "Object is a number : -Infinity\n");
853 break;
854 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000855 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000856 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000857 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
858 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000859 } else {
860 fprintf(output, "Object is a number : %0g\n", cur->floatval);
861 }
862 }
Owen Taylor3473f882001-02-23 17:55:21 +0000863 break;
864 case XPATH_STRING:
865 fprintf(output, "Object is a string : ");
866 xmlDebugDumpString(output, cur->stringval);
867 fprintf(output, "\n");
868 break;
869 case XPATH_POINT:
870 fprintf(output, "Object is a point : index %d in node", cur->index);
871 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
872 fprintf(output, "\n");
873 break;
874 case XPATH_RANGE:
875 if ((cur->user2 == NULL) ||
876 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
877 fprintf(output, "Object is a collapsed range :\n");
878 fprintf(output, shift);
879 if (cur->index >= 0)
880 fprintf(output, "index %d in ", cur->index);
881 fprintf(output, "node\n");
882 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
883 depth + 1);
884 } else {
885 fprintf(output, "Object is a range :\n");
886 fprintf(output, shift);
887 fprintf(output, "From ");
888 if (cur->index >= 0)
889 fprintf(output, "index %d in ", cur->index);
890 fprintf(output, "node\n");
891 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
892 depth + 1);
893 fprintf(output, shift);
894 fprintf(output, "To ");
895 if (cur->index2 >= 0)
896 fprintf(output, "index %d in ", cur->index2);
897 fprintf(output, "node\n");
898 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
899 depth + 1);
900 fprintf(output, "\n");
901 }
902 break;
903 case XPATH_LOCATIONSET:
904#if defined(LIBXML_XPTR_ENABLED)
905 fprintf(output, "Object is a Location Set:\n");
906 xmlXPathDebugDumpLocationSet(output,
907 (xmlLocationSetPtr) cur->user, depth);
908#endif
909 break;
910 case XPATH_USERS:
911 fprintf(output, "Object is user defined\n");
912 break;
913 }
914}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000915
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000916static void
917xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000918 xmlXPathStepOpPtr op, int depth) {
919 int i;
920 char shift[100];
921
922 for (i = 0;((i < depth) && (i < 25));i++)
923 shift[2 * i] = shift[2 * i + 1] = ' ';
924 shift[2 * i] = shift[2 * i + 1] = 0;
925
926 fprintf(output, shift);
927 if (op == NULL) {
928 fprintf(output, "Step is NULL\n");
929 return;
930 }
931 switch (op->op) {
932 case XPATH_OP_END:
933 fprintf(output, "END"); break;
934 case XPATH_OP_AND:
935 fprintf(output, "AND"); break;
936 case XPATH_OP_OR:
937 fprintf(output, "OR"); break;
938 case XPATH_OP_EQUAL:
939 if (op->value)
940 fprintf(output, "EQUAL =");
941 else
942 fprintf(output, "EQUAL !=");
943 break;
944 case XPATH_OP_CMP:
945 if (op->value)
946 fprintf(output, "CMP <");
947 else
948 fprintf(output, "CMP >");
949 if (!op->value2)
950 fprintf(output, "=");
951 break;
952 case XPATH_OP_PLUS:
953 if (op->value == 0)
954 fprintf(output, "PLUS -");
955 else if (op->value == 1)
956 fprintf(output, "PLUS +");
957 else if (op->value == 2)
958 fprintf(output, "PLUS unary -");
959 else if (op->value == 3)
960 fprintf(output, "PLUS unary - -");
961 break;
962 case XPATH_OP_MULT:
963 if (op->value == 0)
964 fprintf(output, "MULT *");
965 else if (op->value == 1)
966 fprintf(output, "MULT div");
967 else
968 fprintf(output, "MULT mod");
969 break;
970 case XPATH_OP_UNION:
971 fprintf(output, "UNION"); break;
972 case XPATH_OP_ROOT:
973 fprintf(output, "ROOT"); break;
974 case XPATH_OP_NODE:
975 fprintf(output, "NODE"); break;
976 case XPATH_OP_RESET:
977 fprintf(output, "RESET"); break;
978 case XPATH_OP_SORT:
979 fprintf(output, "SORT"); break;
980 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000981 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
982 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
983 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000984 const xmlChar *prefix = op->value4;
985 const xmlChar *name = op->value5;
986
987 fprintf(output, "COLLECT ");
988 switch (axis) {
989 case AXIS_ANCESTOR:
990 fprintf(output, " 'ancestors' "); break;
991 case AXIS_ANCESTOR_OR_SELF:
992 fprintf(output, " 'ancestors-or-self' "); break;
993 case AXIS_ATTRIBUTE:
994 fprintf(output, " 'attributes' "); break;
995 case AXIS_CHILD:
996 fprintf(output, " 'child' "); break;
997 case AXIS_DESCENDANT:
998 fprintf(output, " 'descendant' "); break;
999 case AXIS_DESCENDANT_OR_SELF:
1000 fprintf(output, " 'descendant-or-self' "); break;
1001 case AXIS_FOLLOWING:
1002 fprintf(output, " 'following' "); break;
1003 case AXIS_FOLLOWING_SIBLING:
1004 fprintf(output, " 'following-siblings' "); break;
1005 case AXIS_NAMESPACE:
1006 fprintf(output, " 'namespace' "); break;
1007 case AXIS_PARENT:
1008 fprintf(output, " 'parent' "); break;
1009 case AXIS_PRECEDING:
1010 fprintf(output, " 'preceding' "); break;
1011 case AXIS_PRECEDING_SIBLING:
1012 fprintf(output, " 'preceding-sibling' "); break;
1013 case AXIS_SELF:
1014 fprintf(output, " 'self' "); break;
1015 }
1016 switch (test) {
1017 case NODE_TEST_NONE:
1018 fprintf(output, "'none' "); break;
1019 case NODE_TEST_TYPE:
1020 fprintf(output, "'type' "); break;
1021 case NODE_TEST_PI:
1022 fprintf(output, "'PI' "); break;
1023 case NODE_TEST_ALL:
1024 fprintf(output, "'all' "); break;
1025 case NODE_TEST_NS:
1026 fprintf(output, "'namespace' "); break;
1027 case NODE_TEST_NAME:
1028 fprintf(output, "'name' "); break;
1029 }
1030 switch (type) {
1031 case NODE_TYPE_NODE:
1032 fprintf(output, "'node' "); break;
1033 case NODE_TYPE_COMMENT:
1034 fprintf(output, "'comment' "); break;
1035 case NODE_TYPE_TEXT:
1036 fprintf(output, "'text' "); break;
1037 case NODE_TYPE_PI:
1038 fprintf(output, "'PI' "); break;
1039 }
1040 if (prefix != NULL)
1041 fprintf(output, "%s:", prefix);
1042 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001043 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001044 break;
1045
1046 }
1047 case XPATH_OP_VALUE: {
1048 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1049
1050 fprintf(output, "ELEM ");
1051 xmlXPathDebugDumpObject(output, object, 0);
1052 goto finish;
1053 }
1054 case XPATH_OP_VARIABLE: {
1055 const xmlChar *prefix = op->value5;
1056 const xmlChar *name = op->value4;
1057
1058 if (prefix != NULL)
1059 fprintf(output, "VARIABLE %s:%s", prefix, name);
1060 else
1061 fprintf(output, "VARIABLE %s", name);
1062 break;
1063 }
1064 case XPATH_OP_FUNCTION: {
1065 int nbargs = op->value;
1066 const xmlChar *prefix = op->value5;
1067 const xmlChar *name = op->value4;
1068
1069 if (prefix != NULL)
1070 fprintf(output, "FUNCTION %s:%s(%d args)",
1071 prefix, name, nbargs);
1072 else
1073 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1074 break;
1075 }
1076 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1077 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001078 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001079#ifdef LIBXML_XPTR_ENABLED
1080 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1081#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001082 default:
1083 fprintf(output, "UNKNOWN %d\n", op->op); return;
1084 }
1085 fprintf(output, "\n");
1086finish:
1087 if (op->ch1 >= 0)
1088 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1089 if (op->ch2 >= 0)
1090 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1091}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001092
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001093/**
1094 * xmlXPathDebugDumpCompExpr:
1095 * @output: the FILE * for the output
1096 * @comp: the precompiled XPath expression
1097 * @depth: the indentation level.
1098 *
1099 * Dumps the tree of the compiled XPath expression.
1100 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001101void
1102xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1103 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001104 int i;
1105 char shift[100];
1106
Daniel Veillarda82b1822004-11-08 16:24:57 +00001107 if ((output == NULL) || (comp == NULL)) return;
1108
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001109 for (i = 0;((i < depth) && (i < 25));i++)
1110 shift[2 * i] = shift[2 * i + 1] = ' ';
1111 shift[2 * i] = shift[2 * i + 1] = 0;
1112
1113 fprintf(output, shift);
1114
1115 if (comp == NULL) {
1116 fprintf(output, "Compiled Expression is NULL\n");
1117 return;
1118 }
1119 fprintf(output, "Compiled Expression : %d elements\n",
1120 comp->nbStep);
1121 i = comp->last;
1122 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1123}
Daniel Veillard017b1082001-06-21 11:20:21 +00001124#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001125
1126/************************************************************************
1127 * *
1128 * Parser stacks related functions and macros *
1129 * *
1130 ************************************************************************/
1131
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001132/**
1133 * valuePop:
1134 * @ctxt: an XPath evaluation context
1135 *
1136 * Pops the top XPath object from the value stack
1137 *
1138 * Returns the XPath object just removed
1139 */
Daniel Veillard24505b02005-07-28 23:49:35 +00001140xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00001141valuePop(xmlXPathParserContextPtr ctxt)
1142{
1143 xmlXPathObjectPtr ret;
1144
Daniel Veillarda82b1822004-11-08 16:24:57 +00001145 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00001146 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +00001147 ctxt->valueNr--;
1148 if (ctxt->valueNr > 0)
1149 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1150 else
1151 ctxt->value = NULL;
1152 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00001153 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00001154 return (ret);
1155}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001156/**
1157 * valuePush:
1158 * @ctxt: an XPath evaluation context
1159 * @value: the XPath object
1160 *
1161 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001162 *
1163 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001164 */
Daniel Veillard24505b02005-07-28 23:49:35 +00001165int
Daniel Veillard1c732d22002-11-30 11:22:59 +00001166valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1167{
Daniel Veillarda82b1822004-11-08 16:24:57 +00001168 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00001169 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001170 xmlXPathObjectPtr *tmp;
1171
1172 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1173 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00001174 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001175 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00001176 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1177 return (0);
1178 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001179 ctxt->valueMax *= 2;
1180 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00001181 }
1182 ctxt->valueTab[ctxt->valueNr] = value;
1183 ctxt->value = value;
1184 return (ctxt->valueNr++);
1185}
Owen Taylor3473f882001-02-23 17:55:21 +00001186
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001187/**
1188 * xmlXPathPopBoolean:
1189 * @ctxt: an XPath parser context
1190 *
1191 * Pops a boolean from the stack, handling conversion if needed.
1192 * Check error with #xmlXPathCheckError.
1193 *
1194 * Returns the boolean
1195 */
1196int
1197xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1198 xmlXPathObjectPtr obj;
1199 int ret;
1200
1201 obj = valuePop(ctxt);
1202 if (obj == NULL) {
1203 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1204 return(0);
1205 }
William M. Brack08171912003-12-29 02:52:11 +00001206 if (obj->type != XPATH_BOOLEAN)
1207 ret = xmlXPathCastToBoolean(obj);
1208 else
1209 ret = obj->boolval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001210 xmlXPathFreeObject(obj);
1211 return(ret);
1212}
1213
1214/**
1215 * xmlXPathPopNumber:
1216 * @ctxt: an XPath parser context
1217 *
1218 * Pops a number from the stack, handling conversion if needed.
1219 * Check error with #xmlXPathCheckError.
1220 *
1221 * Returns the number
1222 */
1223double
1224xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1225 xmlXPathObjectPtr obj;
1226 double ret;
1227
1228 obj = valuePop(ctxt);
1229 if (obj == NULL) {
1230 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1231 return(0);
1232 }
William M. Brack08171912003-12-29 02:52:11 +00001233 if (obj->type != XPATH_NUMBER)
1234 ret = xmlXPathCastToNumber(obj);
1235 else
1236 ret = obj->floatval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001237 xmlXPathFreeObject(obj);
1238 return(ret);
1239}
1240
1241/**
1242 * xmlXPathPopString:
1243 * @ctxt: an XPath parser context
1244 *
1245 * Pops a string from the stack, handling conversion if needed.
1246 * Check error with #xmlXPathCheckError.
1247 *
1248 * Returns the string
1249 */
1250xmlChar *
1251xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1252 xmlXPathObjectPtr obj;
1253 xmlChar * ret;
1254
1255 obj = valuePop(ctxt);
1256 if (obj == NULL) {
1257 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1258 return(NULL);
1259 }
William M. Brack08171912003-12-29 02:52:11 +00001260 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001261 /* TODO: needs refactoring somewhere else */
1262 if (obj->stringval == ret)
1263 obj->stringval = NULL;
1264 xmlXPathFreeObject(obj);
1265 return(ret);
1266}
1267
1268/**
1269 * xmlXPathPopNodeSet:
1270 * @ctxt: an XPath parser context
1271 *
1272 * Pops a node-set from the stack, handling conversion if needed.
1273 * Check error with #xmlXPathCheckError.
1274 *
1275 * Returns the node-set
1276 */
1277xmlNodeSetPtr
1278xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1279 xmlXPathObjectPtr obj;
1280 xmlNodeSetPtr ret;
1281
Daniel Veillardf2a36f92004-11-08 17:55:01 +00001282 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001283 if (ctxt->value == NULL) {
1284 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1285 return(NULL);
1286 }
1287 if (!xmlXPathStackIsNodeSet(ctxt)) {
1288 xmlXPathSetTypeError(ctxt);
1289 return(NULL);
1290 }
1291 obj = valuePop(ctxt);
1292 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00001293#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00001294 /* to fix memory leak of not clearing obj->user */
1295 if (obj->boolval && obj->user != NULL)
1296 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00001297#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001298 xmlXPathFreeNodeSetList(obj);
1299 return(ret);
1300}
1301
1302/**
1303 * xmlXPathPopExternal:
1304 * @ctxt: an XPath parser context
1305 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001306 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001307 * Check error with #xmlXPathCheckError.
1308 *
1309 * Returns the object
1310 */
1311void *
1312xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1313 xmlXPathObjectPtr obj;
1314 void * ret;
1315
Daniel Veillarda82b1822004-11-08 16:24:57 +00001316 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001317 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1318 return(NULL);
1319 }
1320 if (ctxt->value->type != XPATH_USERS) {
1321 xmlXPathSetTypeError(ctxt);
1322 return(NULL);
1323 }
1324 obj = valuePop(ctxt);
1325 ret = obj->user;
1326 xmlXPathFreeObject(obj);
1327 return(ret);
1328}
1329
Owen Taylor3473f882001-02-23 17:55:21 +00001330/*
1331 * Macros for accessing the content. Those should be used only by the parser,
1332 * and not exported.
1333 *
1334 * Dirty macros, i.e. one need to make assumption on the context to use them
1335 *
1336 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1337 * CUR returns the current xmlChar value, i.e. a 8 bit value
1338 * in ISO-Latin or UTF-8.
1339 * This should be used internally by the parser
1340 * only to compare to ASCII values otherwise it would break when
1341 * running with UTF-8 encoding.
1342 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1343 * to compare on ASCII based substring.
1344 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1345 * strings within the parser.
1346 * CURRENT Returns the current char value, with the full decoding of
1347 * UTF-8 if we are using this mode. It returns an int.
1348 * NEXT Skip to the next character, this does the proper decoding
1349 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1350 * It returns the pointer to the current xmlChar.
1351 */
1352
1353#define CUR (*ctxt->cur)
1354#define SKIP(val) ctxt->cur += (val)
1355#define NXT(val) ctxt->cur[(val)]
1356#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001357#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1358
1359#define COPY_BUF(l,b,i,v) \
1360 if (l == 1) b[i++] = (xmlChar) v; \
1361 else i += xmlCopyChar(l,&b[i],v)
1362
1363#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001364
1365#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001366 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001367
1368#define CURRENT (*ctxt->cur)
1369#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1370
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001371
1372#ifndef DBL_DIG
1373#define DBL_DIG 16
1374#endif
1375#ifndef DBL_EPSILON
1376#define DBL_EPSILON 1E-9
1377#endif
1378
1379#define UPPER_DOUBLE 1E9
1380#define LOWER_DOUBLE 1E-5
1381
1382#define INTEGER_DIGITS DBL_DIG
1383#define FRACTION_DIGITS (DBL_DIG + 1)
1384#define EXPONENT_DIGITS (3 + 2)
1385
1386/**
1387 * xmlXPathFormatNumber:
1388 * @number: number to format
1389 * @buffer: output buffer
1390 * @buffersize: size of output buffer
1391 *
1392 * Convert the number into a string representation.
1393 */
1394static void
1395xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1396{
Daniel Veillardcda96922001-08-21 10:56:31 +00001397 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001398 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001399 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001400 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001401 break;
1402 case -1:
1403 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001404 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001405 break;
1406 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001407 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001408 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001409 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001410 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001411 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001412 } else if (number == ((int) number)) {
1413 char work[30];
1414 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00001415 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001416
1417 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001418 if (value == 0) {
1419 *ptr++ = '0';
1420 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00001421 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001422 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00001423 while ((*cur) && (ptr - buffer < buffersize)) {
1424 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001425 }
1426 }
1427 if (ptr - buffer < buffersize) {
1428 *ptr = 0;
1429 } else if (buffersize > 0) {
1430 ptr--;
1431 *ptr = 0;
1432 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001433 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001434 /* 3 is sign, decimal point, and terminating zero */
1435 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1436 int integer_place, fraction_place;
1437 char *ptr;
1438 char *after_fraction;
1439 double absolute_value;
1440 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001441
Bjorn Reese70a9da52001-04-21 16:57:29 +00001442 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001443
Bjorn Reese70a9da52001-04-21 16:57:29 +00001444 /*
1445 * First choose format - scientific or regular floating point.
1446 * In either case, result is in work, and after_fraction points
1447 * just past the fractional part.
1448 */
1449 if ( ((absolute_value > UPPER_DOUBLE) ||
1450 (absolute_value < LOWER_DOUBLE)) &&
1451 (absolute_value != 0.0) ) {
1452 /* Use scientific notation */
1453 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1454 fraction_place = DBL_DIG - 1;
1455 snprintf(work, sizeof(work),"%*.*e",
1456 integer_place, fraction_place, number);
1457 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001458 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001459 else {
1460 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001461 if (absolute_value > 0.0)
1462 integer_place = 1 + (int)log10(absolute_value);
1463 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001464 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001465 fraction_place = (integer_place > 0)
1466 ? DBL_DIG - integer_place
1467 : DBL_DIG;
1468 size = snprintf(work, sizeof(work), "%0.*f",
1469 fraction_place, number);
1470 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001471 }
1472
Bjorn Reese70a9da52001-04-21 16:57:29 +00001473 /* Remove fractional trailing zeroes */
1474 ptr = after_fraction;
1475 while (*(--ptr) == '0')
1476 ;
1477 if (*ptr != '.')
1478 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001479 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001480
1481 /* Finally copy result back to caller */
1482 size = strlen(work) + 1;
1483 if (size > buffersize) {
1484 work[buffersize - 1] = 0;
1485 size = buffersize;
1486 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001487 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001488 }
1489 break;
1490 }
1491}
1492
Owen Taylor3473f882001-02-23 17:55:21 +00001493
1494/************************************************************************
1495 * *
1496 * Routines to handle NodeSets *
1497 * *
1498 ************************************************************************/
1499
1500/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001501 * xmlXPathOrderDocElems:
1502 * @doc: an input document
1503 *
1504 * Call this routine to speed up XPath computation on static documents.
1505 * This stamps all the element nodes with the document order
1506 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00001507 * field, the value stored is actually - the node number (starting at -1)
1508 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001509 *
William M. Brack08171912003-12-29 02:52:11 +00001510 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001511 * of error.
1512 */
1513long
1514xmlXPathOrderDocElems(xmlDocPtr doc) {
1515 long count = 0;
1516 xmlNodePtr cur;
1517
1518 if (doc == NULL)
1519 return(-1);
1520 cur = doc->children;
1521 while (cur != NULL) {
1522 if (cur->type == XML_ELEMENT_NODE) {
1523 cur->content = (void *) (-(++count));
1524 if (cur->children != NULL) {
1525 cur = cur->children;
1526 continue;
1527 }
1528 }
1529 if (cur->next != NULL) {
1530 cur = cur->next;
1531 continue;
1532 }
1533 do {
1534 cur = cur->parent;
1535 if (cur == NULL)
1536 break;
1537 if (cur == (xmlNodePtr) doc) {
1538 cur = NULL;
1539 break;
1540 }
1541 if (cur->next != NULL) {
1542 cur = cur->next;
1543 break;
1544 }
1545 } while (cur != NULL);
1546 }
1547 return(count);
1548}
1549
1550/**
Owen Taylor3473f882001-02-23 17:55:21 +00001551 * xmlXPathCmpNodes:
1552 * @node1: the first node
1553 * @node2: the second node
1554 *
1555 * Compare two nodes w.r.t document order
1556 *
1557 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00001558 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001559 */
1560int
1561xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1562 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001563 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001564 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001565 xmlNodePtr cur, root;
1566
1567 if ((node1 == NULL) || (node2 == NULL))
1568 return(-2);
1569 /*
1570 * a couple of optimizations which will avoid computations in most cases
1571 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001572 if (node1->type == XML_ATTRIBUTE_NODE) {
1573 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001574 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001575 node1 = node1->parent;
1576 }
1577 if (node2->type == XML_ATTRIBUTE_NODE) {
1578 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001579 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001580 node2 = node2->parent;
1581 }
1582 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001583 if (attr1 == attr2) {
1584 /* not required, but we keep attributes in order */
1585 if (attr1 != 0) {
1586 cur = attrNode2->prev;
1587 while (cur != NULL) {
1588 if (cur == attrNode1)
1589 return (1);
1590 cur = cur->prev;
1591 }
1592 return (-1);
1593 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001594 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001595 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001596 if (attr2 == 1)
1597 return(1);
1598 return(-1);
1599 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001600 if ((node1->type == XML_NAMESPACE_DECL) ||
1601 (node2->type == XML_NAMESPACE_DECL))
1602 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001603 if (node1 == node2->prev)
1604 return(1);
1605 if (node1 == node2->next)
1606 return(-1);
1607
1608 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001609 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001610 */
1611 if ((node1->type == XML_ELEMENT_NODE) &&
1612 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001613 (0 > (long) node1->content) &&
1614 (0 > (long) node2->content) &&
1615 (node1->doc == node2->doc)) {
1616 long l1, l2;
1617
1618 l1 = -((long) node1->content);
1619 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001620 if (l1 < l2)
1621 return(1);
1622 if (l1 > l2)
1623 return(-1);
1624 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001625
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001626 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001627 * compute depth to root
1628 */
1629 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1630 if (cur == node1)
1631 return(1);
1632 depth2++;
1633 }
1634 root = cur;
1635 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1636 if (cur == node2)
1637 return(-1);
1638 depth1++;
1639 }
1640 /*
1641 * Distinct document (or distinct entities :-( ) case.
1642 */
1643 if (root != cur) {
1644 return(-2);
1645 }
1646 /*
1647 * get the nearest common ancestor.
1648 */
1649 while (depth1 > depth2) {
1650 depth1--;
1651 node1 = node1->parent;
1652 }
1653 while (depth2 > depth1) {
1654 depth2--;
1655 node2 = node2->parent;
1656 }
1657 while (node1->parent != node2->parent) {
1658 node1 = node1->parent;
1659 node2 = node2->parent;
1660 /* should not happen but just in case ... */
1661 if ((node1 == NULL) || (node2 == NULL))
1662 return(-2);
1663 }
1664 /*
1665 * Find who's first.
1666 */
Daniel Veillardf49be472004-02-17 11:48:18 +00001667 if (node1 == node2->prev)
1668 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001669 if (node1 == node2->next)
1670 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00001671 /*
1672 * Speedup using document order if availble.
1673 */
1674 if ((node1->type == XML_ELEMENT_NODE) &&
1675 (node2->type == XML_ELEMENT_NODE) &&
1676 (0 > (long) node1->content) &&
1677 (0 > (long) node2->content) &&
1678 (node1->doc == node2->doc)) {
1679 long l1, l2;
1680
1681 l1 = -((long) node1->content);
1682 l2 = -((long) node2->content);
1683 if (l1 < l2)
1684 return(1);
1685 if (l1 > l2)
1686 return(-1);
1687 }
1688
Owen Taylor3473f882001-02-23 17:55:21 +00001689 for (cur = node1->next;cur != NULL;cur = cur->next)
1690 if (cur == node2)
1691 return(1);
1692 return(-1); /* assume there is no sibling list corruption */
1693}
1694
1695/**
1696 * xmlXPathNodeSetSort:
1697 * @set: the node set
1698 *
1699 * Sort the node set in document order
1700 */
1701void
1702xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001703 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001704 xmlNodePtr tmp;
1705
1706 if (set == NULL)
1707 return;
1708
1709 /* Use Shell's sort to sort the node-set */
1710 len = set->nodeNr;
1711 for (incr = len / 2; incr > 0; incr /= 2) {
1712 for (i = incr; i < len; i++) {
1713 j = i - incr;
1714 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001715 if (xmlXPathCmpNodes(set->nodeTab[j],
1716 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001717 tmp = set->nodeTab[j];
1718 set->nodeTab[j] = set->nodeTab[j + incr];
1719 set->nodeTab[j + incr] = tmp;
1720 j -= incr;
1721 } else
1722 break;
1723 }
1724 }
1725 }
1726}
1727
1728#define XML_NODESET_DEFAULT 10
1729/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001730 * xmlXPathNodeSetDupNs:
1731 * @node: the parent node of the namespace XPath node
1732 * @ns: the libxml namespace declaration node.
1733 *
1734 * Namespace node in libxml don't match the XPath semantic. In a node set
1735 * the namespace nodes are duplicated and the next pointer is set to the
1736 * parent node in the XPath semantic.
1737 *
1738 * Returns the newly created object.
1739 */
1740static xmlNodePtr
1741xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1742 xmlNsPtr cur;
1743
1744 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1745 return(NULL);
1746 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1747 return((xmlNodePtr) ns);
1748
1749 /*
1750 * Allocate a new Namespace and fill the fields.
1751 */
1752 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1753 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001754 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001755 return(NULL);
1756 }
1757 memset(cur, 0, sizeof(xmlNs));
1758 cur->type = XML_NAMESPACE_DECL;
1759 if (ns->href != NULL)
1760 cur->href = xmlStrdup(ns->href);
1761 if (ns->prefix != NULL)
1762 cur->prefix = xmlStrdup(ns->prefix);
1763 cur->next = (xmlNsPtr) node;
1764 return((xmlNodePtr) cur);
1765}
1766
1767/**
1768 * xmlXPathNodeSetFreeNs:
1769 * @ns: the XPath namespace node found in a nodeset.
1770 *
William M. Brack08171912003-12-29 02:52:11 +00001771 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001772 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00001773 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001774 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001775void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001776xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1777 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1778 return;
1779
1780 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1781 if (ns->href != NULL)
1782 xmlFree((xmlChar *)ns->href);
1783 if (ns->prefix != NULL)
1784 xmlFree((xmlChar *)ns->prefix);
1785 xmlFree(ns);
1786 }
1787}
1788
1789/**
Owen Taylor3473f882001-02-23 17:55:21 +00001790 * xmlXPathNodeSetCreate:
1791 * @val: an initial xmlNodePtr, or NULL
1792 *
1793 * Create a new xmlNodeSetPtr of type double and of value @val
1794 *
1795 * Returns the newly created object.
1796 */
1797xmlNodeSetPtr
1798xmlXPathNodeSetCreate(xmlNodePtr val) {
1799 xmlNodeSetPtr ret;
1800
1801 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1802 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001803 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001804 return(NULL);
1805 }
1806 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1807 if (val != NULL) {
1808 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1809 sizeof(xmlNodePtr));
1810 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001811 xmlXPathErrMemory(NULL, "creating nodeset\n");
1812 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001813 return(NULL);
1814 }
1815 memset(ret->nodeTab, 0 ,
1816 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1817 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001818 if (val->type == XML_NAMESPACE_DECL) {
1819 xmlNsPtr ns = (xmlNsPtr) val;
1820
1821 ret->nodeTab[ret->nodeNr++] =
1822 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1823 } else
1824 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001825 }
1826 return(ret);
1827}
1828
1829/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001830 * xmlXPathNodeSetContains:
1831 * @cur: the node-set
1832 * @val: the node
1833 *
1834 * checks whether @cur contains @val
1835 *
1836 * Returns true (1) if @cur contains @val, false (0) otherwise
1837 */
1838int
1839xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1840 int i;
1841
Daniel Veillarda82b1822004-11-08 16:24:57 +00001842 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001843 if (val->type == XML_NAMESPACE_DECL) {
1844 for (i = 0; i < cur->nodeNr; i++) {
1845 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1846 xmlNsPtr ns1, ns2;
1847
1848 ns1 = (xmlNsPtr) val;
1849 ns2 = (xmlNsPtr) cur->nodeTab[i];
1850 if (ns1 == ns2)
1851 return(1);
1852 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1853 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1854 return(1);
1855 }
1856 }
1857 } else {
1858 for (i = 0; i < cur->nodeNr; i++) {
1859 if (cur->nodeTab[i] == val)
1860 return(1);
1861 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001862 }
1863 return(0);
1864}
1865
1866/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001867 * xmlXPathNodeSetAddNs:
1868 * @cur: the initial node set
1869 * @node: the hosting node
1870 * @ns: a the namespace node
1871 *
1872 * add a new namespace node to an existing NodeSet
1873 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001874void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001875xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1876 int i;
1877
Daniel Veillarda82b1822004-11-08 16:24:57 +00001878
1879 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
1880 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001881 (node->type != XML_ELEMENT_NODE))
1882 return;
1883
William M. Brack08171912003-12-29 02:52:11 +00001884 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001885 /*
William M. Brack08171912003-12-29 02:52:11 +00001886 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001887 */
1888 for (i = 0;i < cur->nodeNr;i++) {
1889 if ((cur->nodeTab[i] != NULL) &&
1890 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001891 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001892 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1893 return;
1894 }
1895
1896 /*
1897 * grow the nodeTab if needed
1898 */
1899 if (cur->nodeMax == 0) {
1900 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1901 sizeof(xmlNodePtr));
1902 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001903 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001904 return;
1905 }
1906 memset(cur->nodeTab, 0 ,
1907 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1908 cur->nodeMax = XML_NODESET_DEFAULT;
1909 } else if (cur->nodeNr == cur->nodeMax) {
1910 xmlNodePtr *temp;
1911
1912 cur->nodeMax *= 2;
1913 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1914 sizeof(xmlNodePtr));
1915 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001916 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001917 return;
1918 }
1919 cur->nodeTab = temp;
1920 }
1921 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1922}
1923
1924/**
Owen Taylor3473f882001-02-23 17:55:21 +00001925 * xmlXPathNodeSetAdd:
1926 * @cur: the initial node set
1927 * @val: a new xmlNodePtr
1928 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001929 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001930 */
1931void
1932xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1933 int i;
1934
Daniel Veillarda82b1822004-11-08 16:24:57 +00001935 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001936
Daniel Veillardef0b4502003-03-24 13:57:34 +00001937#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001938 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1939 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001940#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001941
William M. Brack08171912003-12-29 02:52:11 +00001942 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001943 /*
William M. Brack08171912003-12-29 02:52:11 +00001944 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00001945 */
1946 for (i = 0;i < cur->nodeNr;i++)
1947 if (cur->nodeTab[i] == val) return;
1948
1949 /*
1950 * grow the nodeTab if needed
1951 */
1952 if (cur->nodeMax == 0) {
1953 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1954 sizeof(xmlNodePtr));
1955 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001956 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001957 return;
1958 }
1959 memset(cur->nodeTab, 0 ,
1960 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1961 cur->nodeMax = XML_NODESET_DEFAULT;
1962 } else if (cur->nodeNr == cur->nodeMax) {
1963 xmlNodePtr *temp;
1964
1965 cur->nodeMax *= 2;
1966 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1967 sizeof(xmlNodePtr));
1968 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001969 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001970 return;
1971 }
1972 cur->nodeTab = temp;
1973 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001974 if (val->type == XML_NAMESPACE_DECL) {
1975 xmlNsPtr ns = (xmlNsPtr) val;
1976
1977 cur->nodeTab[cur->nodeNr++] =
1978 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1979 } else
1980 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001981}
1982
1983/**
1984 * xmlXPathNodeSetAddUnique:
1985 * @cur: the initial node set
1986 * @val: a new xmlNodePtr
1987 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001988 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001989 * when we are sure the node is not already in the set.
1990 */
1991void
1992xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00001993 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001994
Daniel Veillardef0b4502003-03-24 13:57:34 +00001995#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001996 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1997 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001998#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001999
William M. Brack08171912003-12-29 02:52:11 +00002000 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002001 /*
2002 * grow the nodeTab if needed
2003 */
2004 if (cur->nodeMax == 0) {
2005 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2006 sizeof(xmlNodePtr));
2007 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002008 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002009 return;
2010 }
2011 memset(cur->nodeTab, 0 ,
2012 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2013 cur->nodeMax = XML_NODESET_DEFAULT;
2014 } else if (cur->nodeNr == cur->nodeMax) {
2015 xmlNodePtr *temp;
2016
2017 cur->nodeMax *= 2;
2018 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
2019 sizeof(xmlNodePtr));
2020 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002021 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002022 return;
2023 }
2024 cur->nodeTab = temp;
2025 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002026 if (val->type == XML_NAMESPACE_DECL) {
2027 xmlNsPtr ns = (xmlNsPtr) val;
2028
2029 cur->nodeTab[cur->nodeNr++] =
2030 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2031 } else
2032 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00002033}
2034
2035/**
2036 * xmlXPathNodeSetMerge:
2037 * @val1: the first NodeSet or NULL
2038 * @val2: the second NodeSet
2039 *
2040 * Merges two nodesets, all nodes from @val2 are added to @val1
2041 * if @val1 is NULL, a new set is created and copied from @val2
2042 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002043 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002044 */
2045xmlNodeSetPtr
2046xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002047 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00002048
2049 if (val2 == NULL) return(val1);
2050 if (val1 == NULL) {
2051 val1 = xmlXPathNodeSetCreate(NULL);
2052 }
2053
William M. Brack08171912003-12-29 02:52:11 +00002054 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002055 initNr = val1->nodeNr;
2056
2057 for (i = 0;i < val2->nodeNr;i++) {
2058 /*
William M. Brack08171912003-12-29 02:52:11 +00002059 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00002060 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002061 skip = 0;
2062 for (j = 0; j < initNr; j++) {
2063 if (val1->nodeTab[j] == val2->nodeTab[i]) {
2064 skip = 1;
2065 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002066 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
2067 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
2068 xmlNsPtr ns1, ns2;
2069 ns1 = (xmlNsPtr) val1->nodeTab[j];
2070 ns2 = (xmlNsPtr) val2->nodeTab[i];
2071 if ((ns1->next == ns2->next) &&
2072 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
2073 skip = 1;
2074 break;
2075 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002076 }
2077 }
2078 if (skip)
2079 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00002080
2081 /*
2082 * grow the nodeTab if needed
2083 */
2084 if (val1->nodeMax == 0) {
2085 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2086 sizeof(xmlNodePtr));
2087 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002088 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002089 return(NULL);
2090 }
2091 memset(val1->nodeTab, 0 ,
2092 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2093 val1->nodeMax = XML_NODESET_DEFAULT;
2094 } else if (val1->nodeNr == val1->nodeMax) {
2095 xmlNodePtr *temp;
2096
2097 val1->nodeMax *= 2;
2098 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2099 sizeof(xmlNodePtr));
2100 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002101 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002102 return(NULL);
2103 }
2104 val1->nodeTab = temp;
2105 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002106 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2107 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2108
2109 val1->nodeTab[val1->nodeNr++] =
2110 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2111 } else
2112 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002113 }
2114
2115 return(val1);
2116}
2117
2118/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002119 * xmlXPathNodeSetMergeUnique:
2120 * @val1: the first NodeSet or NULL
2121 * @val2: the second NodeSet
2122 *
2123 * Merges two nodesets, all nodes from @val2 are added to @val1
2124 * if @val1 is NULL, a new set is created and copied from @val2
2125 *
2126 * Returns @val1 once extended or NULL in case of error.
2127 */
2128static xmlNodeSetPtr
2129xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002130 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002131
2132 if (val2 == NULL) return(val1);
2133 if (val1 == NULL) {
2134 val1 = xmlXPathNodeSetCreate(NULL);
2135 }
2136
William M. Brack08171912003-12-29 02:52:11 +00002137 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002138
2139 for (i = 0;i < val2->nodeNr;i++) {
2140 /*
2141 * grow the nodeTab if needed
2142 */
2143 if (val1->nodeMax == 0) {
2144 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2145 sizeof(xmlNodePtr));
2146 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002147 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002148 return(NULL);
2149 }
2150 memset(val1->nodeTab, 0 ,
2151 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2152 val1->nodeMax = XML_NODESET_DEFAULT;
2153 } else if (val1->nodeNr == val1->nodeMax) {
2154 xmlNodePtr *temp;
2155
2156 val1->nodeMax *= 2;
2157 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2158 sizeof(xmlNodePtr));
2159 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002160 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002161 return(NULL);
2162 }
2163 val1->nodeTab = temp;
2164 }
2165 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2166 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2167
2168 val1->nodeTab[val1->nodeNr++] =
2169 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2170 } else
2171 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2172 }
2173
2174 return(val1);
2175}
2176
2177/**
Owen Taylor3473f882001-02-23 17:55:21 +00002178 * xmlXPathNodeSetDel:
2179 * @cur: the initial node set
2180 * @val: an xmlNodePtr
2181 *
2182 * Removes an xmlNodePtr from an existing NodeSet
2183 */
2184void
2185xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2186 int i;
2187
2188 if (cur == NULL) return;
2189 if (val == NULL) return;
2190
2191 /*
William M. Brack08171912003-12-29 02:52:11 +00002192 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002193 */
2194 for (i = 0;i < cur->nodeNr;i++)
2195 if (cur->nodeTab[i] == val) break;
2196
William M. Brack08171912003-12-29 02:52:11 +00002197 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002198#ifdef DEBUG
2199 xmlGenericError(xmlGenericErrorContext,
2200 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2201 val->name);
2202#endif
2203 return;
2204 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002205 if ((cur->nodeTab[i] != NULL) &&
2206 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2207 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002208 cur->nodeNr--;
2209 for (;i < cur->nodeNr;i++)
2210 cur->nodeTab[i] = cur->nodeTab[i + 1];
2211 cur->nodeTab[cur->nodeNr] = NULL;
2212}
2213
2214/**
2215 * xmlXPathNodeSetRemove:
2216 * @cur: the initial node set
2217 * @val: the index to remove
2218 *
2219 * Removes an entry from an existing NodeSet list.
2220 */
2221void
2222xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2223 if (cur == NULL) return;
2224 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002225 if ((cur->nodeTab[val] != NULL) &&
2226 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2227 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002228 cur->nodeNr--;
2229 for (;val < cur->nodeNr;val++)
2230 cur->nodeTab[val] = cur->nodeTab[val + 1];
2231 cur->nodeTab[cur->nodeNr] = NULL;
2232}
2233
2234/**
2235 * xmlXPathFreeNodeSet:
2236 * @obj: the xmlNodeSetPtr to free
2237 *
2238 * Free the NodeSet compound (not the actual nodes !).
2239 */
2240void
2241xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2242 if (obj == NULL) return;
2243 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002244 int i;
2245
William M. Brack08171912003-12-29 02:52:11 +00002246 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002247 for (i = 0;i < obj->nodeNr;i++)
2248 if ((obj->nodeTab[i] != NULL) &&
2249 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2250 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002251 xmlFree(obj->nodeTab);
2252 }
Owen Taylor3473f882001-02-23 17:55:21 +00002253 xmlFree(obj);
2254}
2255
2256/**
2257 * xmlXPathFreeValueTree:
2258 * @obj: the xmlNodeSetPtr to free
2259 *
2260 * Free the NodeSet compound and the actual tree, this is different
2261 * from xmlXPathFreeNodeSet()
2262 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002263static void
Owen Taylor3473f882001-02-23 17:55:21 +00002264xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2265 int i;
2266
2267 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002268
2269 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002270 for (i = 0;i < obj->nodeNr;i++) {
2271 if (obj->nodeTab[i] != NULL) {
2272 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2273 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2274 } else {
2275 xmlFreeNodeList(obj->nodeTab[i]);
2276 }
2277 }
2278 }
Owen Taylor3473f882001-02-23 17:55:21 +00002279 xmlFree(obj->nodeTab);
2280 }
Owen Taylor3473f882001-02-23 17:55:21 +00002281 xmlFree(obj);
2282}
2283
2284#if defined(DEBUG) || defined(DEBUG_STEP)
2285/**
2286 * xmlGenericErrorContextNodeSet:
2287 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002288 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002289 *
2290 * Quick display of a NodeSet
2291 */
2292void
2293xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2294 int i;
2295
2296 if (output == NULL) output = xmlGenericErrorContext;
2297 if (obj == NULL) {
2298 fprintf(output, "NodeSet == NULL !\n");
2299 return;
2300 }
2301 if (obj->nodeNr == 0) {
2302 fprintf(output, "NodeSet is empty\n");
2303 return;
2304 }
2305 if (obj->nodeTab == NULL) {
2306 fprintf(output, " nodeTab == NULL !\n");
2307 return;
2308 }
2309 for (i = 0; i < obj->nodeNr; i++) {
2310 if (obj->nodeTab[i] == NULL) {
2311 fprintf(output, " NULL !\n");
2312 return;
2313 }
2314 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2315 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2316 fprintf(output, " /");
2317 else if (obj->nodeTab[i]->name == NULL)
2318 fprintf(output, " noname!");
2319 else fprintf(output, " %s", obj->nodeTab[i]->name);
2320 }
2321 fprintf(output, "\n");
2322}
2323#endif
2324
2325/**
2326 * xmlXPathNewNodeSet:
2327 * @val: the NodePtr value
2328 *
2329 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2330 * it with the single Node @val
2331 *
2332 * Returns the newly created object.
2333 */
2334xmlXPathObjectPtr
2335xmlXPathNewNodeSet(xmlNodePtr val) {
2336 xmlXPathObjectPtr ret;
2337
2338 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2339 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002340 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002341 return(NULL);
2342 }
2343 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2344 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002345 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002346 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002347 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002348 return(ret);
2349}
2350
2351/**
2352 * xmlXPathNewValueTree:
2353 * @val: the NodePtr value
2354 *
2355 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2356 * it with the tree root @val
2357 *
2358 * Returns the newly created object.
2359 */
2360xmlXPathObjectPtr
2361xmlXPathNewValueTree(xmlNodePtr val) {
2362 xmlXPathObjectPtr ret;
2363
2364 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2365 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002366 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002367 return(NULL);
2368 }
2369 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2370 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002371 ret->boolval = 1;
2372 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002373 ret->nodesetval = xmlXPathNodeSetCreate(val);
2374 return(ret);
2375}
2376
2377/**
2378 * xmlXPathNewNodeSetList:
2379 * @val: an existing NodeSet
2380 *
2381 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2382 * it with the Nodeset @val
2383 *
2384 * Returns the newly created object.
2385 */
2386xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002387xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2388{
Owen Taylor3473f882001-02-23 17:55:21 +00002389 xmlXPathObjectPtr ret;
2390 int i;
2391
2392 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002393 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002394 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002395 ret = xmlXPathNewNodeSet(NULL);
2396 else {
2397 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2398 for (i = 1; i < val->nodeNr; ++i)
2399 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2400 }
Owen Taylor3473f882001-02-23 17:55:21 +00002401
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002402 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002403}
2404
2405/**
2406 * xmlXPathWrapNodeSet:
2407 * @val: the NodePtr value
2408 *
2409 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2410 *
2411 * Returns the newly created object.
2412 */
2413xmlXPathObjectPtr
2414xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2415 xmlXPathObjectPtr ret;
2416
2417 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2418 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002419 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002420 return(NULL);
2421 }
2422 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2423 ret->type = XPATH_NODESET;
2424 ret->nodesetval = val;
2425 return(ret);
2426}
2427
2428/**
2429 * xmlXPathFreeNodeSetList:
2430 * @obj: an existing NodeSetList object
2431 *
2432 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2433 * the list contrary to xmlXPathFreeObject().
2434 */
2435void
2436xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2437 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002438 xmlFree(obj);
2439}
2440
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002441/**
2442 * xmlXPathDifference:
2443 * @nodes1: a node-set
2444 * @nodes2: a node-set
2445 *
2446 * Implements the EXSLT - Sets difference() function:
2447 * node-set set:difference (node-set, node-set)
2448 *
2449 * Returns the difference between the two node sets, or nodes1 if
2450 * nodes2 is empty
2451 */
2452xmlNodeSetPtr
2453xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2454 xmlNodeSetPtr ret;
2455 int i, l1;
2456 xmlNodePtr cur;
2457
2458 if (xmlXPathNodeSetIsEmpty(nodes2))
2459 return(nodes1);
2460
2461 ret = xmlXPathNodeSetCreate(NULL);
2462 if (xmlXPathNodeSetIsEmpty(nodes1))
2463 return(ret);
2464
2465 l1 = xmlXPathNodeSetGetLength(nodes1);
2466
2467 for (i = 0; i < l1; i++) {
2468 cur = xmlXPathNodeSetItem(nodes1, i);
2469 if (!xmlXPathNodeSetContains(nodes2, cur))
2470 xmlXPathNodeSetAddUnique(ret, cur);
2471 }
2472 return(ret);
2473}
2474
2475/**
2476 * xmlXPathIntersection:
2477 * @nodes1: a node-set
2478 * @nodes2: a node-set
2479 *
2480 * Implements the EXSLT - Sets intersection() function:
2481 * node-set set:intersection (node-set, node-set)
2482 *
2483 * Returns a node set comprising the nodes that are within both the
2484 * node sets passed as arguments
2485 */
2486xmlNodeSetPtr
2487xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2488 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2489 int i, l1;
2490 xmlNodePtr cur;
2491
2492 if (xmlXPathNodeSetIsEmpty(nodes1))
2493 return(ret);
2494 if (xmlXPathNodeSetIsEmpty(nodes2))
2495 return(ret);
2496
2497 l1 = xmlXPathNodeSetGetLength(nodes1);
2498
2499 for (i = 0; i < l1; i++) {
2500 cur = xmlXPathNodeSetItem(nodes1, i);
2501 if (xmlXPathNodeSetContains(nodes2, cur))
2502 xmlXPathNodeSetAddUnique(ret, cur);
2503 }
2504 return(ret);
2505}
2506
2507/**
2508 * xmlXPathDistinctSorted:
2509 * @nodes: a node-set, sorted by document order
2510 *
2511 * Implements the EXSLT - Sets distinct() function:
2512 * node-set set:distinct (node-set)
2513 *
2514 * Returns a subset of the nodes contained in @nodes, or @nodes if
2515 * it is empty
2516 */
2517xmlNodeSetPtr
2518xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2519 xmlNodeSetPtr ret;
2520 xmlHashTablePtr hash;
2521 int i, l;
2522 xmlChar * strval;
2523 xmlNodePtr cur;
2524
2525 if (xmlXPathNodeSetIsEmpty(nodes))
2526 return(nodes);
2527
2528 ret = xmlXPathNodeSetCreate(NULL);
2529 l = xmlXPathNodeSetGetLength(nodes);
2530 hash = xmlHashCreate (l);
2531 for (i = 0; i < l; i++) {
2532 cur = xmlXPathNodeSetItem(nodes, i);
2533 strval = xmlXPathCastNodeToString(cur);
2534 if (xmlHashLookup(hash, strval) == NULL) {
2535 xmlHashAddEntry(hash, strval, strval);
2536 xmlXPathNodeSetAddUnique(ret, cur);
2537 } else {
2538 xmlFree(strval);
2539 }
2540 }
2541 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2542 return(ret);
2543}
2544
2545/**
2546 * xmlXPathDistinct:
2547 * @nodes: a node-set
2548 *
2549 * Implements the EXSLT - Sets distinct() function:
2550 * node-set set:distinct (node-set)
2551 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2552 * is called with the sorted node-set
2553 *
2554 * Returns a subset of the nodes contained in @nodes, or @nodes if
2555 * it is empty
2556 */
2557xmlNodeSetPtr
2558xmlXPathDistinct (xmlNodeSetPtr nodes) {
2559 if (xmlXPathNodeSetIsEmpty(nodes))
2560 return(nodes);
2561
2562 xmlXPathNodeSetSort(nodes);
2563 return(xmlXPathDistinctSorted(nodes));
2564}
2565
2566/**
2567 * xmlXPathHasSameNodes:
2568 * @nodes1: a node-set
2569 * @nodes2: a node-set
2570 *
2571 * Implements the EXSLT - Sets has-same-nodes function:
2572 * boolean set:has-same-node(node-set, node-set)
2573 *
2574 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2575 * otherwise
2576 */
2577int
2578xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2579 int i, l;
2580 xmlNodePtr cur;
2581
2582 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2583 xmlXPathNodeSetIsEmpty(nodes2))
2584 return(0);
2585
2586 l = xmlXPathNodeSetGetLength(nodes1);
2587 for (i = 0; i < l; i++) {
2588 cur = xmlXPathNodeSetItem(nodes1, i);
2589 if (xmlXPathNodeSetContains(nodes2, cur))
2590 return(1);
2591 }
2592 return(0);
2593}
2594
2595/**
2596 * xmlXPathNodeLeadingSorted:
2597 * @nodes: a node-set, sorted by document order
2598 * @node: a node
2599 *
2600 * Implements the EXSLT - Sets leading() function:
2601 * node-set set:leading (node-set, node-set)
2602 *
2603 * Returns the nodes in @nodes that precede @node in document order,
2604 * @nodes if @node is NULL or an empty node-set if @nodes
2605 * doesn't contain @node
2606 */
2607xmlNodeSetPtr
2608xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2609 int i, l;
2610 xmlNodePtr cur;
2611 xmlNodeSetPtr ret;
2612
2613 if (node == NULL)
2614 return(nodes);
2615
2616 ret = xmlXPathNodeSetCreate(NULL);
2617 if (xmlXPathNodeSetIsEmpty(nodes) ||
2618 (!xmlXPathNodeSetContains(nodes, node)))
2619 return(ret);
2620
2621 l = xmlXPathNodeSetGetLength(nodes);
2622 for (i = 0; i < l; i++) {
2623 cur = xmlXPathNodeSetItem(nodes, i);
2624 if (cur == node)
2625 break;
2626 xmlXPathNodeSetAddUnique(ret, cur);
2627 }
2628 return(ret);
2629}
2630
2631/**
2632 * xmlXPathNodeLeading:
2633 * @nodes: a node-set
2634 * @node: a node
2635 *
2636 * Implements the EXSLT - Sets leading() function:
2637 * node-set set:leading (node-set, node-set)
2638 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2639 * is called.
2640 *
2641 * Returns the nodes in @nodes that precede @node in document order,
2642 * @nodes if @node is NULL or an empty node-set if @nodes
2643 * doesn't contain @node
2644 */
2645xmlNodeSetPtr
2646xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2647 xmlXPathNodeSetSort(nodes);
2648 return(xmlXPathNodeLeadingSorted(nodes, node));
2649}
2650
2651/**
2652 * xmlXPathLeadingSorted:
2653 * @nodes1: a node-set, sorted by document order
2654 * @nodes2: a node-set, sorted by document order
2655 *
2656 * Implements the EXSLT - Sets leading() function:
2657 * node-set set:leading (node-set, node-set)
2658 *
2659 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2660 * in document order, @nodes1 if @nodes2 is NULL or empty or
2661 * an empty node-set if @nodes1 doesn't contain @nodes2
2662 */
2663xmlNodeSetPtr
2664xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2665 if (xmlXPathNodeSetIsEmpty(nodes2))
2666 return(nodes1);
2667 return(xmlXPathNodeLeadingSorted(nodes1,
2668 xmlXPathNodeSetItem(nodes2, 1)));
2669}
2670
2671/**
2672 * xmlXPathLeading:
2673 * @nodes1: a node-set
2674 * @nodes2: a node-set
2675 *
2676 * Implements the EXSLT - Sets leading() function:
2677 * node-set set:leading (node-set, node-set)
2678 * @nodes1 and @nodes2 are sorted by document order, then
2679 * #exslSetsLeadingSorted is called.
2680 *
2681 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2682 * in document order, @nodes1 if @nodes2 is NULL or empty or
2683 * an empty node-set if @nodes1 doesn't contain @nodes2
2684 */
2685xmlNodeSetPtr
2686xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2687 if (xmlXPathNodeSetIsEmpty(nodes2))
2688 return(nodes1);
2689 if (xmlXPathNodeSetIsEmpty(nodes1))
2690 return(xmlXPathNodeSetCreate(NULL));
2691 xmlXPathNodeSetSort(nodes1);
2692 xmlXPathNodeSetSort(nodes2);
2693 return(xmlXPathNodeLeadingSorted(nodes1,
2694 xmlXPathNodeSetItem(nodes2, 1)));
2695}
2696
2697/**
2698 * xmlXPathNodeTrailingSorted:
2699 * @nodes: a node-set, sorted by document order
2700 * @node: a node
2701 *
2702 * Implements the EXSLT - Sets trailing() function:
2703 * node-set set:trailing (node-set, node-set)
2704 *
2705 * Returns the nodes in @nodes that follow @node in document order,
2706 * @nodes if @node is NULL or an empty node-set if @nodes
2707 * doesn't contain @node
2708 */
2709xmlNodeSetPtr
2710xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2711 int i, l;
2712 xmlNodePtr cur;
2713 xmlNodeSetPtr ret;
2714
2715 if (node == NULL)
2716 return(nodes);
2717
2718 ret = xmlXPathNodeSetCreate(NULL);
2719 if (xmlXPathNodeSetIsEmpty(nodes) ||
2720 (!xmlXPathNodeSetContains(nodes, node)))
2721 return(ret);
2722
2723 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002724 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002725 cur = xmlXPathNodeSetItem(nodes, i);
2726 if (cur == node)
2727 break;
2728 xmlXPathNodeSetAddUnique(ret, cur);
2729 }
2730 return(ret);
2731}
2732
2733/**
2734 * xmlXPathNodeTrailing:
2735 * @nodes: a node-set
2736 * @node: a node
2737 *
2738 * Implements the EXSLT - Sets trailing() function:
2739 * node-set set:trailing (node-set, node-set)
2740 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2741 * is called.
2742 *
2743 * Returns the nodes in @nodes that follow @node in document order,
2744 * @nodes if @node is NULL or an empty node-set if @nodes
2745 * doesn't contain @node
2746 */
2747xmlNodeSetPtr
2748xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2749 xmlXPathNodeSetSort(nodes);
2750 return(xmlXPathNodeTrailingSorted(nodes, node));
2751}
2752
2753/**
2754 * xmlXPathTrailingSorted:
2755 * @nodes1: a node-set, sorted by document order
2756 * @nodes2: a node-set, sorted by document order
2757 *
2758 * Implements the EXSLT - Sets trailing() function:
2759 * node-set set:trailing (node-set, node-set)
2760 *
2761 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2762 * in document order, @nodes1 if @nodes2 is NULL or empty or
2763 * an empty node-set if @nodes1 doesn't contain @nodes2
2764 */
2765xmlNodeSetPtr
2766xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2767 if (xmlXPathNodeSetIsEmpty(nodes2))
2768 return(nodes1);
2769 return(xmlXPathNodeTrailingSorted(nodes1,
2770 xmlXPathNodeSetItem(nodes2, 0)));
2771}
2772
2773/**
2774 * xmlXPathTrailing:
2775 * @nodes1: a node-set
2776 * @nodes2: a node-set
2777 *
2778 * Implements the EXSLT - Sets trailing() function:
2779 * node-set set:trailing (node-set, node-set)
2780 * @nodes1 and @nodes2 are sorted by document order, then
2781 * #xmlXPathTrailingSorted is called.
2782 *
2783 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2784 * in document order, @nodes1 if @nodes2 is NULL or empty or
2785 * an empty node-set if @nodes1 doesn't contain @nodes2
2786 */
2787xmlNodeSetPtr
2788xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2789 if (xmlXPathNodeSetIsEmpty(nodes2))
2790 return(nodes1);
2791 if (xmlXPathNodeSetIsEmpty(nodes1))
2792 return(xmlXPathNodeSetCreate(NULL));
2793 xmlXPathNodeSetSort(nodes1);
2794 xmlXPathNodeSetSort(nodes2);
2795 return(xmlXPathNodeTrailingSorted(nodes1,
2796 xmlXPathNodeSetItem(nodes2, 0)));
2797}
2798
Owen Taylor3473f882001-02-23 17:55:21 +00002799/************************************************************************
2800 * *
2801 * Routines to handle extra functions *
2802 * *
2803 ************************************************************************/
2804
2805/**
2806 * xmlXPathRegisterFunc:
2807 * @ctxt: the XPath context
2808 * @name: the function name
2809 * @f: the function implementation or NULL
2810 *
2811 * Register a new function. If @f is NULL it unregisters the function
2812 *
2813 * Returns 0 in case of success, -1 in case of error
2814 */
2815int
2816xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2817 xmlXPathFunction f) {
2818 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2819}
2820
2821/**
2822 * xmlXPathRegisterFuncNS:
2823 * @ctxt: the XPath context
2824 * @name: the function name
2825 * @ns_uri: the function namespace URI
2826 * @f: the function implementation or NULL
2827 *
2828 * Register a new function. If @f is NULL it unregisters the function
2829 *
2830 * Returns 0 in case of success, -1 in case of error
2831 */
2832int
2833xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2834 const xmlChar *ns_uri, xmlXPathFunction f) {
2835 if (ctxt == NULL)
2836 return(-1);
2837 if (name == NULL)
2838 return(-1);
2839
2840 if (ctxt->funcHash == NULL)
2841 ctxt->funcHash = xmlHashCreate(0);
2842 if (ctxt->funcHash == NULL)
2843 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002844 if (f == NULL)
2845 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00002846 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00002847}
2848
2849/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002850 * xmlXPathRegisterFuncLookup:
2851 * @ctxt: the XPath context
2852 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002853 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002854 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002855 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002856 */
2857void
2858xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2859 xmlXPathFuncLookupFunc f,
2860 void *funcCtxt) {
2861 if (ctxt == NULL)
2862 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002863 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002864 ctxt->funcLookupData = funcCtxt;
2865}
2866
2867/**
Owen Taylor3473f882001-02-23 17:55:21 +00002868 * xmlXPathFunctionLookup:
2869 * @ctxt: the XPath context
2870 * @name: the function name
2871 *
2872 * Search in the Function array of the context for the given
2873 * function.
2874 *
2875 * Returns the xmlXPathFunction or NULL if not found
2876 */
2877xmlXPathFunction
2878xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002879 if (ctxt == NULL)
2880 return (NULL);
2881
2882 if (ctxt->funcLookupFunc != NULL) {
2883 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002884 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002885
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002886 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002887 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002888 if (ret != NULL)
2889 return(ret);
2890 }
Owen Taylor3473f882001-02-23 17:55:21 +00002891 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2892}
2893
2894/**
2895 * xmlXPathFunctionLookupNS:
2896 * @ctxt: the XPath context
2897 * @name: the function name
2898 * @ns_uri: the function namespace URI
2899 *
2900 * Search in the Function array of the context for the given
2901 * function.
2902 *
2903 * Returns the xmlXPathFunction or NULL if not found
2904 */
2905xmlXPathFunction
2906xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2907 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00002908 xmlXPathFunction ret;
2909
Owen Taylor3473f882001-02-23 17:55:21 +00002910 if (ctxt == NULL)
2911 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002912 if (name == NULL)
2913 return(NULL);
2914
Thomas Broyerba4ad322001-07-26 16:55:21 +00002915 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002916 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002917
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002918 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002919 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002920 if (ret != NULL)
2921 return(ret);
2922 }
2923
2924 if (ctxt->funcHash == NULL)
2925 return(NULL);
2926
William M. Brackad0e67c2004-12-01 14:35:10 +00002927 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
2928 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002929}
2930
2931/**
2932 * xmlXPathRegisteredFuncsCleanup:
2933 * @ctxt: the XPath context
2934 *
2935 * Cleanup the XPath context data associated to registered functions
2936 */
2937void
2938xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2939 if (ctxt == NULL)
2940 return;
2941
2942 xmlHashFree(ctxt->funcHash, NULL);
2943 ctxt->funcHash = NULL;
2944}
2945
2946/************************************************************************
2947 * *
William M. Brack08171912003-12-29 02:52:11 +00002948 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00002949 * *
2950 ************************************************************************/
2951
2952/**
2953 * xmlXPathRegisterVariable:
2954 * @ctxt: the XPath context
2955 * @name: the variable name
2956 * @value: the variable value or NULL
2957 *
2958 * Register a new variable value. If @value is NULL it unregisters
2959 * the variable
2960 *
2961 * Returns 0 in case of success, -1 in case of error
2962 */
2963int
2964xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2965 xmlXPathObjectPtr value) {
2966 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2967}
2968
2969/**
2970 * xmlXPathRegisterVariableNS:
2971 * @ctxt: the XPath context
2972 * @name: the variable name
2973 * @ns_uri: the variable namespace URI
2974 * @value: the variable value or NULL
2975 *
2976 * Register a new variable value. If @value is NULL it unregisters
2977 * the variable
2978 *
2979 * Returns 0 in case of success, -1 in case of error
2980 */
2981int
2982xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2983 const xmlChar *ns_uri,
2984 xmlXPathObjectPtr value) {
2985 if (ctxt == NULL)
2986 return(-1);
2987 if (name == NULL)
2988 return(-1);
2989
2990 if (ctxt->varHash == NULL)
2991 ctxt->varHash = xmlHashCreate(0);
2992 if (ctxt->varHash == NULL)
2993 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002994 if (value == NULL)
2995 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2996 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002997 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2998 (void *) value,
2999 (xmlHashDeallocator)xmlXPathFreeObject));
3000}
3001
3002/**
3003 * xmlXPathRegisterVariableLookup:
3004 * @ctxt: the XPath context
3005 * @f: the lookup function
3006 * @data: the lookup data
3007 *
3008 * register an external mechanism to do variable lookup
3009 */
3010void
3011xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
3012 xmlXPathVariableLookupFunc f, void *data) {
3013 if (ctxt == NULL)
3014 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00003015 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00003016 ctxt->varLookupData = data;
3017}
3018
3019/**
3020 * xmlXPathVariableLookup:
3021 * @ctxt: the XPath context
3022 * @name: the variable name
3023 *
3024 * Search in the Variable array of the context for the given
3025 * variable value.
3026 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003027 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003028 */
3029xmlXPathObjectPtr
3030xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3031 if (ctxt == NULL)
3032 return(NULL);
3033
3034 if (ctxt->varLookupFunc != NULL) {
3035 xmlXPathObjectPtr ret;
3036
3037 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3038 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00003039 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003040 }
3041 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3042}
3043
3044/**
3045 * xmlXPathVariableLookupNS:
3046 * @ctxt: the XPath context
3047 * @name: the variable name
3048 * @ns_uri: the variable namespace URI
3049 *
3050 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00003051 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00003052 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003053 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003054 */
3055xmlXPathObjectPtr
3056xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3057 const xmlChar *ns_uri) {
3058 if (ctxt == NULL)
3059 return(NULL);
3060
3061 if (ctxt->varLookupFunc != NULL) {
3062 xmlXPathObjectPtr ret;
3063
3064 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3065 (ctxt->varLookupData, name, ns_uri);
3066 if (ret != NULL) return(ret);
3067 }
3068
3069 if (ctxt->varHash == NULL)
3070 return(NULL);
3071 if (name == NULL)
3072 return(NULL);
3073
Daniel Veillard8c357d52001-07-03 23:43:33 +00003074 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3075 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00003076}
3077
3078/**
3079 * xmlXPathRegisteredVariablesCleanup:
3080 * @ctxt: the XPath context
3081 *
3082 * Cleanup the XPath context data associated to registered variables
3083 */
3084void
3085xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3086 if (ctxt == NULL)
3087 return;
3088
Daniel Veillard76d66f42001-05-16 21:05:17 +00003089 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00003090 ctxt->varHash = NULL;
3091}
3092
3093/**
3094 * xmlXPathRegisterNs:
3095 * @ctxt: the XPath context
3096 * @prefix: the namespace prefix
3097 * @ns_uri: the namespace name
3098 *
3099 * Register a new namespace. If @ns_uri is NULL it unregisters
3100 * the namespace
3101 *
3102 * Returns 0 in case of success, -1 in case of error
3103 */
3104int
3105xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3106 const xmlChar *ns_uri) {
3107 if (ctxt == NULL)
3108 return(-1);
3109 if (prefix == NULL)
3110 return(-1);
3111
3112 if (ctxt->nsHash == NULL)
3113 ctxt->nsHash = xmlHashCreate(10);
3114 if (ctxt->nsHash == NULL)
3115 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003116 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003117 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003118 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003119 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003120 (xmlHashDeallocator)xmlFree));
3121}
3122
3123/**
3124 * xmlXPathNsLookup:
3125 * @ctxt: the XPath context
3126 * @prefix: the namespace prefix value
3127 *
3128 * Search in the namespace declaration array of the context for the given
3129 * namespace name associated to the given prefix
3130 *
3131 * Returns the value or NULL if not found
3132 */
3133const xmlChar *
3134xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3135 if (ctxt == NULL)
3136 return(NULL);
3137 if (prefix == NULL)
3138 return(NULL);
3139
3140#ifdef XML_XML_NAMESPACE
3141 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3142 return(XML_XML_NAMESPACE);
3143#endif
3144
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003145 if (ctxt->namespaces != NULL) {
3146 int i;
3147
3148 for (i = 0;i < ctxt->nsNr;i++) {
3149 if ((ctxt->namespaces[i] != NULL) &&
3150 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3151 return(ctxt->namespaces[i]->href);
3152 }
3153 }
Owen Taylor3473f882001-02-23 17:55:21 +00003154
3155 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3156}
3157
3158/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003159 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003160 * @ctxt: the XPath context
3161 *
3162 * Cleanup the XPath context data associated to registered variables
3163 */
3164void
3165xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3166 if (ctxt == NULL)
3167 return;
3168
Daniel Veillard42766c02002-08-22 20:52:17 +00003169 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003170 ctxt->nsHash = NULL;
3171}
3172
3173/************************************************************************
3174 * *
3175 * Routines to handle Values *
3176 * *
3177 ************************************************************************/
3178
William M. Brack08171912003-12-29 02:52:11 +00003179/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003180
3181/**
3182 * xmlXPathNewFloat:
3183 * @val: the double value
3184 *
3185 * Create a new xmlXPathObjectPtr of type double and of value @val
3186 *
3187 * Returns the newly created object.
3188 */
3189xmlXPathObjectPtr
3190xmlXPathNewFloat(double val) {
3191 xmlXPathObjectPtr ret;
3192
3193 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3194 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003195 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003196 return(NULL);
3197 }
3198 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3199 ret->type = XPATH_NUMBER;
3200 ret->floatval = val;
3201 return(ret);
3202}
3203
3204/**
3205 * xmlXPathNewBoolean:
3206 * @val: the boolean value
3207 *
3208 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3209 *
3210 * Returns the newly created object.
3211 */
3212xmlXPathObjectPtr
3213xmlXPathNewBoolean(int val) {
3214 xmlXPathObjectPtr ret;
3215
3216 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3217 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003218 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003219 return(NULL);
3220 }
3221 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3222 ret->type = XPATH_BOOLEAN;
3223 ret->boolval = (val != 0);
3224 return(ret);
3225}
3226
3227/**
3228 * xmlXPathNewString:
3229 * @val: the xmlChar * value
3230 *
3231 * Create a new xmlXPathObjectPtr of type string and of value @val
3232 *
3233 * Returns the newly created object.
3234 */
3235xmlXPathObjectPtr
3236xmlXPathNewString(const xmlChar *val) {
3237 xmlXPathObjectPtr ret;
3238
3239 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3240 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003241 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003242 return(NULL);
3243 }
3244 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3245 ret->type = XPATH_STRING;
3246 if (val != NULL)
3247 ret->stringval = xmlStrdup(val);
3248 else
3249 ret->stringval = xmlStrdup((const xmlChar *)"");
3250 return(ret);
3251}
3252
3253/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003254 * xmlXPathWrapString:
3255 * @val: the xmlChar * value
3256 *
3257 * Wraps the @val string into an XPath object.
3258 *
3259 * Returns the newly created object.
3260 */
3261xmlXPathObjectPtr
3262xmlXPathWrapString (xmlChar *val) {
3263 xmlXPathObjectPtr ret;
3264
3265 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3266 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003267 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003268 return(NULL);
3269 }
3270 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3271 ret->type = XPATH_STRING;
3272 ret->stringval = val;
3273 return(ret);
3274}
3275
3276/**
Owen Taylor3473f882001-02-23 17:55:21 +00003277 * xmlXPathNewCString:
3278 * @val: the char * value
3279 *
3280 * Create a new xmlXPathObjectPtr of type string and of value @val
3281 *
3282 * Returns the newly created object.
3283 */
3284xmlXPathObjectPtr
3285xmlXPathNewCString(const char *val) {
3286 xmlXPathObjectPtr ret;
3287
3288 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3289 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003290 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003291 return(NULL);
3292 }
3293 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3294 ret->type = XPATH_STRING;
3295 ret->stringval = xmlStrdup(BAD_CAST val);
3296 return(ret);
3297}
3298
3299/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003300 * xmlXPathWrapCString:
3301 * @val: the char * value
3302 *
3303 * Wraps a string into an XPath object.
3304 *
3305 * Returns the newly created object.
3306 */
3307xmlXPathObjectPtr
3308xmlXPathWrapCString (char * val) {
3309 return(xmlXPathWrapString((xmlChar *)(val)));
3310}
3311
3312/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003313 * xmlXPathWrapExternal:
3314 * @val: the user data
3315 *
3316 * Wraps the @val data into an XPath object.
3317 *
3318 * Returns the newly created object.
3319 */
3320xmlXPathObjectPtr
3321xmlXPathWrapExternal (void *val) {
3322 xmlXPathObjectPtr ret;
3323
3324 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3325 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003326 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003327 return(NULL);
3328 }
3329 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3330 ret->type = XPATH_USERS;
3331 ret->user = val;
3332 return(ret);
3333}
3334
3335/**
Owen Taylor3473f882001-02-23 17:55:21 +00003336 * xmlXPathObjectCopy:
3337 * @val: the original object
3338 *
3339 * allocate a new copy of a given object
3340 *
3341 * Returns the newly created object.
3342 */
3343xmlXPathObjectPtr
3344xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3345 xmlXPathObjectPtr ret;
3346
3347 if (val == NULL)
3348 return(NULL);
3349
3350 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3351 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003352 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003353 return(NULL);
3354 }
3355 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3356 switch (val->type) {
3357 case XPATH_BOOLEAN:
3358 case XPATH_NUMBER:
3359 case XPATH_POINT:
3360 case XPATH_RANGE:
3361 break;
3362 case XPATH_STRING:
3363 ret->stringval = xmlStrdup(val->stringval);
3364 break;
3365 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00003366#if 0
3367/*
3368 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
3369 this previous handling is no longer correct, and can cause some serious
3370 problems (ref. bug 145547)
3371*/
Owen Taylor3473f882001-02-23 17:55:21 +00003372 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003373 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003374 xmlNodePtr cur, tmp;
3375 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003376
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003377 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003378 top = xmlNewDoc(NULL);
3379 top->name = (char *)
3380 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003381 ret->user = top;
3382 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003383 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003384 cur = val->nodesetval->nodeTab[0]->children;
3385 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003386 tmp = xmlDocCopyNode(cur, top, 1);
3387 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003388 cur = cur->next;
3389 }
3390 }
William M. Bracke9449c52004-07-11 14:41:20 +00003391
Daniel Veillard9adc0462003-03-24 18:39:54 +00003392 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003393 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003394 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003395 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003396 break;
William M. Bracke9449c52004-07-11 14:41:20 +00003397#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003398 case XPATH_NODESET:
3399 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003400 /* Do not deallocate the copied tree value */
3401 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003402 break;
3403 case XPATH_LOCATIONSET:
3404#ifdef LIBXML_XPTR_ENABLED
3405 {
3406 xmlLocationSetPtr loc = val->user;
3407 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3408 break;
3409 }
3410#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003411 case XPATH_USERS:
3412 ret->user = val->user;
3413 break;
3414 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003415 xmlGenericError(xmlGenericErrorContext,
3416 "xmlXPathObjectCopy: unsupported type %d\n",
3417 val->type);
3418 break;
3419 }
3420 return(ret);
3421}
3422
3423/**
3424 * xmlXPathFreeObject:
3425 * @obj: the object to free
3426 *
3427 * Free up an xmlXPathObjectPtr object.
3428 */
3429void
3430xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3431 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003432 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003433 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00003434#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003435 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003436 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003437 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003438 } else
3439#endif
3440 if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003441 xmlXPathFreeValueTree(obj->nodesetval);
3442 } else {
3443 if (obj->nodesetval != NULL)
3444 xmlXPathFreeNodeSet(obj->nodesetval);
3445 }
Owen Taylor3473f882001-02-23 17:55:21 +00003446#ifdef LIBXML_XPTR_ENABLED
3447 } else if (obj->type == XPATH_LOCATIONSET) {
3448 if (obj->user != NULL)
3449 xmlXPtrFreeLocationSet(obj->user);
3450#endif
3451 } else if (obj->type == XPATH_STRING) {
3452 if (obj->stringval != NULL)
3453 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003454 }
3455
Owen Taylor3473f882001-02-23 17:55:21 +00003456 xmlFree(obj);
3457}
3458
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003459
3460/************************************************************************
3461 * *
3462 * Type Casting Routines *
3463 * *
3464 ************************************************************************/
3465
3466/**
3467 * xmlXPathCastBooleanToString:
3468 * @val: a boolean
3469 *
3470 * Converts a boolean to its string value.
3471 *
3472 * Returns a newly allocated string.
3473 */
3474xmlChar *
3475xmlXPathCastBooleanToString (int val) {
3476 xmlChar *ret;
3477 if (val)
3478 ret = xmlStrdup((const xmlChar *) "true");
3479 else
3480 ret = xmlStrdup((const xmlChar *) "false");
3481 return(ret);
3482}
3483
3484/**
3485 * xmlXPathCastNumberToString:
3486 * @val: a number
3487 *
3488 * Converts a number to its string value.
3489 *
3490 * Returns a newly allocated string.
3491 */
3492xmlChar *
3493xmlXPathCastNumberToString (double val) {
3494 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003495 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003496 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003497 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003498 break;
3499 case -1:
3500 ret = xmlStrdup((const xmlChar *) "-Infinity");
3501 break;
3502 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003503 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003504 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003505 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3506 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003507 } else {
3508 /* could be improved */
3509 char buf[100];
3510 xmlXPathFormatNumber(val, buf, 100);
3511 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;
5519 if (cur == NULL) return(NULL);
5520 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;
5849 if (cur == NULL) return(NULL);
5850 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;
8875 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008876 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008877 xmlXPathTypeVal type;
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 Veillard8bda20f2005-08-24 09:36:47 +00008940 type = (xmlXPathTypeVal) 0;
8941 test = (xmlXPathTestVal) 0;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008942 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008943 if (test == 0)
8944 return;
8945
Daniel Veillarded6c5492005-07-23 15:00:22 +00008946 if ((prefix != NULL) && (ctxt->context != NULL) &&
8947 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
8948 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
8949 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
8950 }
8951 }
Owen Taylor3473f882001-02-23 17:55:21 +00008952#ifdef DEBUG_STEP
8953 xmlGenericError(xmlGenericErrorContext,
8954 "Basis : computing new set\n");
8955#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008956
Owen Taylor3473f882001-02-23 17:55:21 +00008957#ifdef DEBUG_STEP
8958 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008959 if (ctxt->value == NULL)
8960 xmlGenericError(xmlGenericErrorContext, "no value\n");
8961 else if (ctxt->value->nodesetval == NULL)
8962 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8963 else
8964 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008965#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008966
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008967#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008968eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008969#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008970 op1 = ctxt->comp->last;
8971 ctxt->comp->last = -1;
8972
Owen Taylor3473f882001-02-23 17:55:21 +00008973 SKIP_BLANKS;
8974 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008975 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008976 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008977
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008978#ifdef LIBXML_XPTR_ENABLED
8979 if (rangeto) {
8980 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8981 } else
8982#endif
8983 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8984 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008985
Owen Taylor3473f882001-02-23 17:55:21 +00008986 }
8987#ifdef DEBUG_STEP
8988 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008989 if (ctxt->value == NULL)
8990 xmlGenericError(xmlGenericErrorContext, "no value\n");
8991 else if (ctxt->value->nodesetval == NULL)
8992 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8993 else
8994 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8995 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008996#endif
8997}
8998
8999/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009000 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00009001 * @ctxt: the XPath Parser context
9002 *
9003 * [3] RelativeLocationPath ::= Step
9004 * | RelativeLocationPath '/' Step
9005 * | AbbreviatedRelativeLocationPath
9006 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
9007 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009008 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00009009 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009010static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009011xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00009012(xmlXPathParserContextPtr ctxt) {
9013 SKIP_BLANKS;
9014 if ((CUR == '/') && (NXT(1) == '/')) {
9015 SKIP(2);
9016 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009017 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9018 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009019 } else if (CUR == '/') {
9020 NEXT;
9021 SKIP_BLANKS;
9022 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009023 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009024 SKIP_BLANKS;
9025 while (CUR == '/') {
9026 if ((CUR == '/') && (NXT(1) == '/')) {
9027 SKIP(2);
9028 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009029 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00009030 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009031 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009032 } else if (CUR == '/') {
9033 NEXT;
9034 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009035 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009036 }
9037 SKIP_BLANKS;
9038 }
9039}
9040
9041/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009042 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00009043 * @ctxt: the XPath Parser context
9044 *
9045 * [1] LocationPath ::= RelativeLocationPath
9046 * | AbsoluteLocationPath
9047 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
9048 * | AbbreviatedAbsoluteLocationPath
9049 * [10] AbbreviatedAbsoluteLocationPath ::=
9050 * '//' RelativeLocationPath
9051 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009052 * Compile a location path
9053 *
Owen Taylor3473f882001-02-23 17:55:21 +00009054 * // is short for /descendant-or-self::node()/. For example,
9055 * //para is short for /descendant-or-self::node()/child::para and
9056 * so will select any para element in the document (even a para element
9057 * that is a document element will be selected by //para since the
9058 * document element node is a child of the root node); div//para is
9059 * short for div/descendant-or-self::node()/child::para and so will
9060 * select all para descendants of div children.
9061 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009062static void
9063xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009064 SKIP_BLANKS;
9065 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009066 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009067 } else {
9068 while (CUR == '/') {
9069 if ((CUR == '/') && (NXT(1) == '/')) {
9070 SKIP(2);
9071 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009072 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9073 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009074 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009075 } else if (CUR == '/') {
9076 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00009077 SKIP_BLANKS;
9078 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +00009079 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00009080 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009081 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009082 }
9083 }
9084 }
9085}
9086
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009087/************************************************************************
9088 * *
9089 * XPath precompiled expression evaluation *
9090 * *
9091 ************************************************************************/
9092
Daniel Veillardf06307e2001-07-03 10:35:50 +00009093static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009094xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
9095
9096/**
9097 * xmlXPathNodeCollectAndTest:
9098 * @ctxt: the XPath Parser context
9099 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009100 * @first: pointer to the first element in document order
9101 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009102 *
9103 * This is the function implementing a step: based on the current list
9104 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009105 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009106 *
9107 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00009108 *
William M. Brack08171912003-12-29 02:52:11 +00009109 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009110 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009111static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009112xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009113 xmlXPathStepOpPtr op,
9114 xmlNodePtr * first, xmlNodePtr * last)
9115{
William M. Brack78637da2003-07-31 14:47:38 +00009116 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9117 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9118 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009119 const xmlChar *prefix = op->value4;
9120 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009121 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009122
9123#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009124 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009125#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009126 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009127 xmlNodeSetPtr ret, list;
9128 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009129 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00009130 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009131 xmlNodePtr cur = NULL;
9132 xmlXPathObjectPtr obj;
9133 xmlNodeSetPtr nodelist;
9134 xmlNodePtr tmp;
9135
Daniel Veillardf06307e2001-07-03 10:35:50 +00009136 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009137 obj = valuePop(ctxt);
9138 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009139 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009140 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009141 URI = xmlXPathNsLookup(ctxt->context, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009142 if (URI == NULL) {
9143 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009144 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009145 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009146 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009147#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009148 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009149#endif
9150 switch (axis) {
9151 case AXIS_ANCESTOR:
9152#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009153 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009154#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009155 first = NULL;
9156 next = xmlXPathNextAncestor;
9157 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009158 case AXIS_ANCESTOR_OR_SELF:
9159#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009160 xmlGenericError(xmlGenericErrorContext,
9161 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009162#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009163 first = NULL;
9164 next = xmlXPathNextAncestorOrSelf;
9165 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009166 case AXIS_ATTRIBUTE:
9167#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009168 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009169#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009170 first = NULL;
9171 last = NULL;
9172 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009173 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009174 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009175 case AXIS_CHILD:
9176#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009177 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009178#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009179 last = NULL;
9180 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009181 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009182 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009183 case AXIS_DESCENDANT:
9184#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009185 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009186#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009187 last = NULL;
9188 next = xmlXPathNextDescendant;
9189 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009190 case AXIS_DESCENDANT_OR_SELF:
9191#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009192 xmlGenericError(xmlGenericErrorContext,
9193 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009194#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009195 last = NULL;
9196 next = xmlXPathNextDescendantOrSelf;
9197 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009198 case AXIS_FOLLOWING:
9199#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009200 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009201#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009202 last = NULL;
9203 next = xmlXPathNextFollowing;
9204 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009205 case AXIS_FOLLOWING_SIBLING:
9206#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009207 xmlGenericError(xmlGenericErrorContext,
9208 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009209#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009210 last = NULL;
9211 next = xmlXPathNextFollowingSibling;
9212 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009213 case AXIS_NAMESPACE:
9214#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009215 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009216#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009217 first = NULL;
9218 last = NULL;
9219 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009220 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009221 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009222 case AXIS_PARENT:
9223#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009224 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009225#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009226 first = NULL;
9227 next = xmlXPathNextParent;
9228 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009229 case AXIS_PRECEDING:
9230#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009231 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009232#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009233 first = NULL;
9234 next = xmlXPathNextPrecedingInternal;
9235 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009236 case AXIS_PRECEDING_SIBLING:
9237#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009238 xmlGenericError(xmlGenericErrorContext,
9239 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009240#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009241 first = NULL;
9242 next = xmlXPathNextPrecedingSibling;
9243 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009244 case AXIS_SELF:
9245#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009246 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009247#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009248 first = NULL;
9249 last = NULL;
9250 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009251 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009252 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009253 }
William M. Brack2c19a7b2005-04-10 01:03:23 +00009254 if (next == NULL) {
9255 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009256 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009257 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009258
9259 nodelist = obj->nodesetval;
9260 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009261 xmlXPathFreeObject(obj);
9262 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9263 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009264 }
9265 addNode = xmlXPathNodeSetAddUnique;
9266 ret = NULL;
9267#ifdef DEBUG_STEP
9268 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009269 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009270 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009271 case NODE_TEST_NONE:
9272 xmlGenericError(xmlGenericErrorContext,
9273 " searching for none !!!\n");
9274 break;
9275 case NODE_TEST_TYPE:
9276 xmlGenericError(xmlGenericErrorContext,
9277 " searching for type %d\n", type);
9278 break;
9279 case NODE_TEST_PI:
9280 xmlGenericError(xmlGenericErrorContext,
9281 " searching for PI !!!\n");
9282 break;
9283 case NODE_TEST_ALL:
9284 xmlGenericError(xmlGenericErrorContext,
9285 " searching for *\n");
9286 break;
9287 case NODE_TEST_NS:
9288 xmlGenericError(xmlGenericErrorContext,
9289 " searching for namespace %s\n",
9290 prefix);
9291 break;
9292 case NODE_TEST_NAME:
9293 xmlGenericError(xmlGenericErrorContext,
9294 " searching for name %s\n", name);
9295 if (prefix != NULL)
9296 xmlGenericError(xmlGenericErrorContext,
9297 " with namespace %s\n", prefix);
9298 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009299 }
9300 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9301#endif
9302 /*
9303 * 2.3 Node Tests
9304 * - For the attribute axis, the principal node type is attribute.
9305 * - For the namespace axis, the principal node type is namespace.
9306 * - For other axes, the principal node type is element.
9307 *
9308 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009309 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009310 * select all element children of the context node
9311 */
9312 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009313 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009314 ctxt->context->node = nodelist->nodeTab[i];
9315
Daniel Veillardf06307e2001-07-03 10:35:50 +00009316 cur = NULL;
9317 list = xmlXPathNodeSetCreate(NULL);
9318 do {
9319 cur = next(ctxt, cur);
9320 if (cur == NULL)
9321 break;
9322 if ((first != NULL) && (*first == cur))
9323 break;
9324 if (((t % 256) == 0) &&
9325 (first != NULL) && (*first != NULL) &&
9326 (xmlXPathCmpNodes(*first, cur) >= 0))
9327 break;
9328 if ((last != NULL) && (*last == cur))
9329 break;
9330 if (((t % 256) == 0) &&
9331 (last != NULL) && (*last != NULL) &&
9332 (xmlXPathCmpNodes(cur, *last) >= 0))
9333 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009334 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009335#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009336 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9337#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009338 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009339 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009340 ctxt->context->node = tmp;
William M. Brack2c19a7b2005-04-10 01:03:23 +00009341 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009342 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009343 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009344 if ((cur->type == type) ||
9345 ((type == NODE_TYPE_NODE) &&
9346 ((cur->type == XML_DOCUMENT_NODE) ||
9347 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9348 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009349 (cur->type == XML_NAMESPACE_DECL) ||
9350 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009351 (cur->type == XML_PI_NODE) ||
9352 (cur->type == XML_COMMENT_NODE) ||
9353 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009354 (cur->type == XML_TEXT_NODE))) ||
9355 ((type == NODE_TYPE_TEXT) &&
9356 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009357#ifdef DEBUG_STEP
9358 n++;
9359#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009360 addNode(list, cur);
9361 }
9362 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009363 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009364 if (cur->type == XML_PI_NODE) {
9365 if ((name != NULL) &&
9366 (!xmlStrEqual(name, cur->name)))
9367 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009368#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009369 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009370#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009371 addNode(list, cur);
9372 }
9373 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009374 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009375 if (axis == AXIS_ATTRIBUTE) {
9376 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009377#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009378 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009379#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009380 addNode(list, cur);
9381 }
9382 } else if (axis == AXIS_NAMESPACE) {
9383 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009384#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009385 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009386#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009387 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9388 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009389 }
9390 } else {
9391 if (cur->type == XML_ELEMENT_NODE) {
9392 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009393#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009394 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009395#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009396 addNode(list, cur);
9397 } else if ((cur->ns != NULL) &&
9398 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009399#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009400 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009401#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009402 addNode(list, cur);
9403 }
9404 }
9405 }
9406 break;
9407 case NODE_TEST_NS:{
9408 TODO;
9409 break;
9410 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009411 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009412 switch (cur->type) {
9413 case XML_ELEMENT_NODE:
9414 if (xmlStrEqual(name, cur->name)) {
9415 if (prefix == NULL) {
9416 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009417#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009418 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009419#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009420 addNode(list, cur);
9421 }
9422 } else {
9423 if ((cur->ns != NULL) &&
9424 (xmlStrEqual(URI,
9425 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009426#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009427 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009428#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009429 addNode(list, cur);
9430 }
9431 }
9432 }
9433 break;
9434 case XML_ATTRIBUTE_NODE:{
9435 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009436
Daniel Veillardf06307e2001-07-03 10:35:50 +00009437 if (xmlStrEqual(name, attr->name)) {
9438 if (prefix == NULL) {
9439 if ((attr->ns == NULL) ||
9440 (attr->ns->prefix == NULL)) {
9441#ifdef DEBUG_STEP
9442 n++;
9443#endif
9444 addNode(list,
9445 (xmlNodePtr) attr);
9446 }
9447 } else {
9448 if ((attr->ns != NULL) &&
9449 (xmlStrEqual(URI,
9450 attr->ns->
9451 href))) {
9452#ifdef DEBUG_STEP
9453 n++;
9454#endif
9455 addNode(list,
9456 (xmlNodePtr) attr);
9457 }
9458 }
9459 }
9460 break;
9461 }
9462 case XML_NAMESPACE_DECL:
9463 if (cur->type == XML_NAMESPACE_DECL) {
9464 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009465
Daniel Veillardf06307e2001-07-03 10:35:50 +00009466 if ((ns->prefix != NULL) && (name != NULL)
9467 && (xmlStrEqual(ns->prefix, name))) {
9468#ifdef DEBUG_STEP
9469 n++;
9470#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009471 xmlXPathNodeSetAddNs(list,
9472 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009473 }
9474 }
9475 break;
9476 default:
9477 break;
9478 }
9479 break;
9480 break;
9481 }
9482 } while (cur != NULL);
9483
9484 /*
9485 * If there is some predicate filtering do it now
9486 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009487 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009488 xmlXPathObjectPtr obj2;
9489
9490 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9491 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9492 CHECK_TYPE0(XPATH_NODESET);
9493 obj2 = valuePop(ctxt);
9494 list = obj2->nodesetval;
9495 obj2->nodesetval = NULL;
9496 xmlXPathFreeObject(obj2);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009497 if (ctxt->error != XPATH_EXPRESSION_OK) {
9498 xmlXPathFreeObject(obj);
9499 xmlXPathFreeNodeSet(list);
9500 return(0);
9501 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009502 }
9503 if (ret == NULL) {
9504 ret = list;
9505 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009506 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009507 xmlXPathFreeNodeSet(list);
9508 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009509 }
9510 ctxt->context->node = tmp;
9511#ifdef DEBUG_STEP
9512 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009513 "\nExamined %d nodes, found %d nodes at that step\n",
9514 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009515#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009516 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009517 if ((obj->boolval) && (obj->user != NULL)) {
9518 ctxt->value->boolval = 1;
9519 ctxt->value->user = obj->user;
9520 obj->user = NULL;
9521 obj->boolval = 0;
9522 }
9523 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009524 return(t);
9525}
9526
9527/**
9528 * xmlXPathNodeCollectAndTestNth:
9529 * @ctxt: the XPath Parser context
9530 * @op: the XPath precompiled step operation
9531 * @indx: the index to collect
9532 * @first: pointer to the first element in document order
9533 * @last: pointer to the last element in document order
9534 *
9535 * This is the function implementing a step: based on the current list
9536 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009537 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009538 *
9539 * Pushes the new NodeSet resulting from the search.
9540 * Returns the number of node traversed
9541 */
9542static int
9543xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9544 xmlXPathStepOpPtr op, int indx,
9545 xmlNodePtr * first, xmlNodePtr * last)
9546{
William M. Brack78637da2003-07-31 14:47:38 +00009547 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9548 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9549 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009550 const xmlChar *prefix = op->value4;
9551 const xmlChar *name = op->value5;
9552 const xmlChar *URI = NULL;
9553 int n = 0, t = 0;
9554
9555 int i;
9556 xmlNodeSetPtr list;
9557 xmlXPathTraversalFunction next = NULL;
9558 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9559 xmlNodePtr cur = NULL;
9560 xmlXPathObjectPtr obj;
9561 xmlNodeSetPtr nodelist;
9562 xmlNodePtr tmp;
9563
9564 CHECK_TYPE0(XPATH_NODESET);
9565 obj = valuePop(ctxt);
9566 addNode = xmlXPathNodeSetAdd;
9567 if (prefix != NULL) {
9568 URI = xmlXPathNsLookup(ctxt->context, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009569 if (URI == NULL) {
9570 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009571 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009572 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009573 }
9574#ifdef DEBUG_STEP_NTH
9575 xmlGenericError(xmlGenericErrorContext, "new step : ");
9576 if (first != NULL) {
9577 if (*first != NULL)
9578 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9579 (*first)->name);
9580 else
9581 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9582 }
9583 if (last != NULL) {
9584 if (*last != NULL)
9585 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9586 (*last)->name);
9587 else
9588 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9589 }
9590#endif
9591 switch (axis) {
9592 case AXIS_ANCESTOR:
9593#ifdef DEBUG_STEP_NTH
9594 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9595#endif
9596 first = NULL;
9597 next = xmlXPathNextAncestor;
9598 break;
9599 case AXIS_ANCESTOR_OR_SELF:
9600#ifdef DEBUG_STEP_NTH
9601 xmlGenericError(xmlGenericErrorContext,
9602 "axis 'ancestors-or-self' ");
9603#endif
9604 first = NULL;
9605 next = xmlXPathNextAncestorOrSelf;
9606 break;
9607 case AXIS_ATTRIBUTE:
9608#ifdef DEBUG_STEP_NTH
9609 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9610#endif
9611 first = NULL;
9612 last = NULL;
9613 next = xmlXPathNextAttribute;
9614 break;
9615 case AXIS_CHILD:
9616#ifdef DEBUG_STEP_NTH
9617 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9618#endif
9619 last = NULL;
9620 next = xmlXPathNextChild;
9621 break;
9622 case AXIS_DESCENDANT:
9623#ifdef DEBUG_STEP_NTH
9624 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9625#endif
9626 last = NULL;
9627 next = xmlXPathNextDescendant;
9628 break;
9629 case AXIS_DESCENDANT_OR_SELF:
9630#ifdef DEBUG_STEP_NTH
9631 xmlGenericError(xmlGenericErrorContext,
9632 "axis 'descendant-or-self' ");
9633#endif
9634 last = NULL;
9635 next = xmlXPathNextDescendantOrSelf;
9636 break;
9637 case AXIS_FOLLOWING:
9638#ifdef DEBUG_STEP_NTH
9639 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9640#endif
9641 last = NULL;
9642 next = xmlXPathNextFollowing;
9643 break;
9644 case AXIS_FOLLOWING_SIBLING:
9645#ifdef DEBUG_STEP_NTH
9646 xmlGenericError(xmlGenericErrorContext,
9647 "axis 'following-siblings' ");
9648#endif
9649 last = NULL;
9650 next = xmlXPathNextFollowingSibling;
9651 break;
9652 case AXIS_NAMESPACE:
9653#ifdef DEBUG_STEP_NTH
9654 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9655#endif
9656 last = NULL;
9657 first = NULL;
9658 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9659 break;
9660 case AXIS_PARENT:
9661#ifdef DEBUG_STEP_NTH
9662 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9663#endif
9664 first = NULL;
9665 next = xmlXPathNextParent;
9666 break;
9667 case AXIS_PRECEDING:
9668#ifdef DEBUG_STEP_NTH
9669 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9670#endif
9671 first = NULL;
9672 next = xmlXPathNextPrecedingInternal;
9673 break;
9674 case AXIS_PRECEDING_SIBLING:
9675#ifdef DEBUG_STEP_NTH
9676 xmlGenericError(xmlGenericErrorContext,
9677 "axis 'preceding-sibling' ");
9678#endif
9679 first = NULL;
9680 next = xmlXPathNextPrecedingSibling;
9681 break;
9682 case AXIS_SELF:
9683#ifdef DEBUG_STEP_NTH
9684 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9685#endif
9686 first = NULL;
9687 last = NULL;
9688 next = xmlXPathNextSelf;
9689 break;
9690 }
William M. Brack2c19a7b2005-04-10 01:03:23 +00009691 if (next == NULL) {
9692 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009693 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009694 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009695
9696 nodelist = obj->nodesetval;
9697 if (nodelist == NULL) {
9698 xmlXPathFreeObject(obj);
9699 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9700 return(0);
9701 }
9702 addNode = xmlXPathNodeSetAddUnique;
9703#ifdef DEBUG_STEP_NTH
9704 xmlGenericError(xmlGenericErrorContext,
9705 " context contains %d nodes\n", nodelist->nodeNr);
9706 switch (test) {
9707 case NODE_TEST_NONE:
9708 xmlGenericError(xmlGenericErrorContext,
9709 " searching for none !!!\n");
9710 break;
9711 case NODE_TEST_TYPE:
9712 xmlGenericError(xmlGenericErrorContext,
9713 " searching for type %d\n", type);
9714 break;
9715 case NODE_TEST_PI:
9716 xmlGenericError(xmlGenericErrorContext,
9717 " searching for PI !!!\n");
9718 break;
9719 case NODE_TEST_ALL:
9720 xmlGenericError(xmlGenericErrorContext,
9721 " searching for *\n");
9722 break;
9723 case NODE_TEST_NS:
9724 xmlGenericError(xmlGenericErrorContext,
9725 " searching for namespace %s\n",
9726 prefix);
9727 break;
9728 case NODE_TEST_NAME:
9729 xmlGenericError(xmlGenericErrorContext,
9730 " searching for name %s\n", name);
9731 if (prefix != NULL)
9732 xmlGenericError(xmlGenericErrorContext,
9733 " with namespace %s\n", prefix);
9734 break;
9735 }
9736 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9737#endif
9738 /*
9739 * 2.3 Node Tests
9740 * - For the attribute axis, the principal node type is attribute.
9741 * - For the namespace axis, the principal node type is namespace.
9742 * - For other axes, the principal node type is element.
9743 *
9744 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009745 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009746 * select all element children of the context node
9747 */
9748 tmp = ctxt->context->node;
9749 list = xmlXPathNodeSetCreate(NULL);
9750 for (i = 0; i < nodelist->nodeNr; i++) {
9751 ctxt->context->node = nodelist->nodeTab[i];
9752
9753 cur = NULL;
9754 n = 0;
9755 do {
9756 cur = next(ctxt, cur);
9757 if (cur == NULL)
9758 break;
9759 if ((first != NULL) && (*first == cur))
9760 break;
9761 if (((t % 256) == 0) &&
9762 (first != NULL) && (*first != NULL) &&
9763 (xmlXPathCmpNodes(*first, cur) >= 0))
9764 break;
9765 if ((last != NULL) && (*last == cur))
9766 break;
9767 if (((t % 256) == 0) &&
9768 (last != NULL) && (*last != NULL) &&
9769 (xmlXPathCmpNodes(cur, *last) >= 0))
9770 break;
9771 t++;
9772 switch (test) {
9773 case NODE_TEST_NONE:
9774 ctxt->context->node = tmp;
9775 STRANGE return(0);
9776 case NODE_TEST_TYPE:
9777 if ((cur->type == type) ||
9778 ((type == NODE_TYPE_NODE) &&
9779 ((cur->type == XML_DOCUMENT_NODE) ||
9780 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9781 (cur->type == XML_ELEMENT_NODE) ||
9782 (cur->type == XML_PI_NODE) ||
9783 (cur->type == XML_COMMENT_NODE) ||
9784 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009785 (cur->type == XML_TEXT_NODE))) ||
9786 ((type == NODE_TYPE_TEXT) &&
9787 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009788 n++;
9789 if (n == indx)
9790 addNode(list, cur);
9791 }
9792 break;
9793 case NODE_TEST_PI:
9794 if (cur->type == XML_PI_NODE) {
9795 if ((name != NULL) &&
9796 (!xmlStrEqual(name, cur->name)))
9797 break;
9798 n++;
9799 if (n == indx)
9800 addNode(list, cur);
9801 }
9802 break;
9803 case NODE_TEST_ALL:
9804 if (axis == AXIS_ATTRIBUTE) {
9805 if (cur->type == XML_ATTRIBUTE_NODE) {
9806 n++;
9807 if (n == indx)
9808 addNode(list, cur);
9809 }
9810 } else if (axis == AXIS_NAMESPACE) {
9811 if (cur->type == XML_NAMESPACE_DECL) {
9812 n++;
9813 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009814 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9815 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009816 }
9817 } else {
9818 if (cur->type == XML_ELEMENT_NODE) {
9819 if (prefix == NULL) {
9820 n++;
9821 if (n == indx)
9822 addNode(list, cur);
9823 } else if ((cur->ns != NULL) &&
9824 (xmlStrEqual(URI, cur->ns->href))) {
9825 n++;
9826 if (n == indx)
9827 addNode(list, cur);
9828 }
9829 }
9830 }
9831 break;
9832 case NODE_TEST_NS:{
9833 TODO;
9834 break;
9835 }
9836 case NODE_TEST_NAME:
9837 switch (cur->type) {
9838 case XML_ELEMENT_NODE:
9839 if (xmlStrEqual(name, cur->name)) {
9840 if (prefix == NULL) {
9841 if (cur->ns == NULL) {
9842 n++;
9843 if (n == indx)
9844 addNode(list, cur);
9845 }
9846 } else {
9847 if ((cur->ns != NULL) &&
9848 (xmlStrEqual(URI,
9849 cur->ns->href))) {
9850 n++;
9851 if (n == indx)
9852 addNode(list, cur);
9853 }
9854 }
9855 }
9856 break;
9857 case XML_ATTRIBUTE_NODE:{
9858 xmlAttrPtr attr = (xmlAttrPtr) cur;
9859
9860 if (xmlStrEqual(name, attr->name)) {
9861 if (prefix == NULL) {
9862 if ((attr->ns == NULL) ||
9863 (attr->ns->prefix == NULL)) {
9864 n++;
9865 if (n == indx)
9866 addNode(list, cur);
9867 }
9868 } else {
9869 if ((attr->ns != NULL) &&
9870 (xmlStrEqual(URI,
9871 attr->ns->
9872 href))) {
9873 n++;
9874 if (n == indx)
9875 addNode(list, cur);
9876 }
9877 }
9878 }
9879 break;
9880 }
9881 case XML_NAMESPACE_DECL:
9882 if (cur->type == XML_NAMESPACE_DECL) {
9883 xmlNsPtr ns = (xmlNsPtr) cur;
9884
9885 if ((ns->prefix != NULL) && (name != NULL)
9886 && (xmlStrEqual(ns->prefix, name))) {
9887 n++;
9888 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009889 xmlXPathNodeSetAddNs(list,
9890 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009891 }
9892 }
9893 break;
9894 default:
9895 break;
9896 }
9897 break;
9898 break;
9899 }
9900 } while (n < indx);
9901 }
9902 ctxt->context->node = tmp;
9903#ifdef DEBUG_STEP_NTH
9904 xmlGenericError(xmlGenericErrorContext,
9905 "\nExamined %d nodes, found %d nodes at that step\n",
9906 t, list->nodeNr);
9907#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009908 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009909 if ((obj->boolval) && (obj->user != NULL)) {
9910 ctxt->value->boolval = 1;
9911 ctxt->value->user = obj->user;
9912 obj->user = NULL;
9913 obj->boolval = 0;
9914 }
9915 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009916 return(t);
9917}
9918
9919/**
9920 * xmlXPathCompOpEvalFirst:
9921 * @ctxt: the XPath parser context with the compiled expression
9922 * @op: an XPath compiled operation
9923 * @first: the first elem found so far
9924 *
9925 * Evaluate the Precompiled XPath operation searching only the first
9926 * element in document order
9927 *
9928 * Returns the number of examined objects.
9929 */
9930static int
9931xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9932 xmlXPathStepOpPtr op, xmlNodePtr * first)
9933{
9934 int total = 0, cur;
9935 xmlXPathCompExprPtr comp;
9936 xmlXPathObjectPtr arg1, arg2;
9937
Daniel Veillard556c6682001-10-06 09:59:51 +00009938 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009939 comp = ctxt->comp;
9940 switch (op->op) {
9941 case XPATH_OP_END:
9942 return (0);
9943 case XPATH_OP_UNION:
9944 total =
9945 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9946 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009947 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009948 if ((ctxt->value != NULL)
9949 && (ctxt->value->type == XPATH_NODESET)
9950 && (ctxt->value->nodesetval != NULL)
9951 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9952 /*
9953 * limit tree traversing to first node in the result
9954 */
9955 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9956 *first = ctxt->value->nodesetval->nodeTab[0];
9957 }
9958 cur =
9959 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9960 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009961 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009962 CHECK_TYPE0(XPATH_NODESET);
9963 arg2 = valuePop(ctxt);
9964
9965 CHECK_TYPE0(XPATH_NODESET);
9966 arg1 = valuePop(ctxt);
9967
9968 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9969 arg2->nodesetval);
9970 valuePush(ctxt, arg1);
9971 xmlXPathFreeObject(arg2);
9972 /* optimizer */
9973 if (total > cur)
9974 xmlXPathCompSwap(op);
9975 return (total + cur);
9976 case XPATH_OP_ROOT:
9977 xmlXPathRoot(ctxt);
9978 return (0);
9979 case XPATH_OP_NODE:
9980 if (op->ch1 != -1)
9981 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009982 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009983 if (op->ch2 != -1)
9984 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009985 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009986 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9987 return (total);
9988 case XPATH_OP_RESET:
9989 if (op->ch1 != -1)
9990 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009991 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009992 if (op->ch2 != -1)
9993 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009994 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009995 ctxt->context->node = NULL;
9996 return (total);
9997 case XPATH_OP_COLLECT:{
9998 if (op->ch1 == -1)
9999 return (total);
10000
10001 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010002 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010003
10004 /*
10005 * Optimization for [n] selection where n is a number
10006 */
10007 if ((op->ch2 != -1) &&
10008 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10009 (comp->steps[op->ch2].ch1 == -1) &&
10010 (comp->steps[op->ch2].ch2 != -1) &&
10011 (comp->steps[comp->steps[op->ch2].ch2].op ==
10012 XPATH_OP_VALUE)) {
10013 xmlXPathObjectPtr val;
10014
10015 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10016 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10017 int indx = (int) val->floatval;
10018
10019 if (val->floatval == (float) indx) {
10020 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
10021 first, NULL);
10022 return (total);
10023 }
10024 }
10025 }
10026 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
10027 return (total);
10028 }
10029 case XPATH_OP_VALUE:
10030 valuePush(ctxt,
10031 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10032 return (0);
10033 case XPATH_OP_SORT:
10034 if (op->ch1 != -1)
10035 total +=
10036 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10037 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010038 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010039 if ((ctxt->value != NULL)
10040 && (ctxt->value->type == XPATH_NODESET)
10041 && (ctxt->value->nodesetval != NULL))
10042 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10043 return (total);
10044 default:
10045 return (xmlXPathCompOpEval(ctxt, op));
10046 }
10047}
10048
10049/**
10050 * xmlXPathCompOpEvalLast:
10051 * @ctxt: the XPath parser context with the compiled expression
10052 * @op: an XPath compiled operation
10053 * @last: the last elem found so far
10054 *
10055 * Evaluate the Precompiled XPath operation searching only the last
10056 * element in document order
10057 *
William M. Brack08171912003-12-29 02:52:11 +000010058 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000010059 */
10060static int
10061xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
10062 xmlNodePtr * last)
10063{
10064 int total = 0, cur;
10065 xmlXPathCompExprPtr comp;
10066 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000010067 xmlNodePtr bak;
10068 xmlDocPtr bakd;
10069 int pp;
10070 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010071
Daniel Veillard556c6682001-10-06 09:59:51 +000010072 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010073 comp = ctxt->comp;
10074 switch (op->op) {
10075 case XPATH_OP_END:
10076 return (0);
10077 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000010078 bakd = ctxt->context->doc;
10079 bak = ctxt->context->node;
10080 pp = ctxt->context->proximityPosition;
10081 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010082 total =
10083 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010084 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010085 if ((ctxt->value != NULL)
10086 && (ctxt->value->type == XPATH_NODESET)
10087 && (ctxt->value->nodesetval != NULL)
10088 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10089 /*
10090 * limit tree traversing to first node in the result
10091 */
10092 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10093 *last =
10094 ctxt->value->nodesetval->nodeTab[ctxt->value->
10095 nodesetval->nodeNr -
10096 1];
10097 }
William M. Brackce4fc562004-01-22 02:47:18 +000010098 ctxt->context->doc = bakd;
10099 ctxt->context->node = bak;
10100 ctxt->context->proximityPosition = pp;
10101 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010102 cur =
10103 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010104 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010105 if ((ctxt->value != NULL)
10106 && (ctxt->value->type == XPATH_NODESET)
10107 && (ctxt->value->nodesetval != NULL)
10108 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10109 }
10110 CHECK_TYPE0(XPATH_NODESET);
10111 arg2 = valuePop(ctxt);
10112
10113 CHECK_TYPE0(XPATH_NODESET);
10114 arg1 = valuePop(ctxt);
10115
10116 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10117 arg2->nodesetval);
10118 valuePush(ctxt, arg1);
10119 xmlXPathFreeObject(arg2);
10120 /* optimizer */
10121 if (total > cur)
10122 xmlXPathCompSwap(op);
10123 return (total + cur);
10124 case XPATH_OP_ROOT:
10125 xmlXPathRoot(ctxt);
10126 return (0);
10127 case XPATH_OP_NODE:
10128 if (op->ch1 != -1)
10129 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010130 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010131 if (op->ch2 != -1)
10132 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010133 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010134 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10135 return (total);
10136 case XPATH_OP_RESET:
10137 if (op->ch1 != -1)
10138 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010139 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010140 if (op->ch2 != -1)
10141 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010142 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010143 ctxt->context->node = NULL;
10144 return (total);
10145 case XPATH_OP_COLLECT:{
10146 if (op->ch1 == -1)
10147 return (0);
10148
10149 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010150 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010151
10152 /*
10153 * Optimization for [n] selection where n is a number
10154 */
10155 if ((op->ch2 != -1) &&
10156 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10157 (comp->steps[op->ch2].ch1 == -1) &&
10158 (comp->steps[op->ch2].ch2 != -1) &&
10159 (comp->steps[comp->steps[op->ch2].ch2].op ==
10160 XPATH_OP_VALUE)) {
10161 xmlXPathObjectPtr val;
10162
10163 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10164 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10165 int indx = (int) val->floatval;
10166
10167 if (val->floatval == (float) indx) {
10168 total +=
10169 xmlXPathNodeCollectAndTestNth(ctxt, op,
10170 indx, NULL,
10171 last);
10172 return (total);
10173 }
10174 }
10175 }
10176 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10177 return (total);
10178 }
10179 case XPATH_OP_VALUE:
10180 valuePush(ctxt,
10181 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10182 return (0);
10183 case XPATH_OP_SORT:
10184 if (op->ch1 != -1)
10185 total +=
10186 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10187 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010188 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010189 if ((ctxt->value != NULL)
10190 && (ctxt->value->type == XPATH_NODESET)
10191 && (ctxt->value->nodesetval != NULL))
10192 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10193 return (total);
10194 default:
10195 return (xmlXPathCompOpEval(ctxt, op));
10196 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010197}
10198
Owen Taylor3473f882001-02-23 17:55:21 +000010199/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010200 * xmlXPathCompOpEval:
10201 * @ctxt: the XPath parser context with the compiled expression
10202 * @op: an XPath compiled operation
10203 *
10204 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010205 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010206 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010207static int
10208xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10209{
10210 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010211 int equal, ret;
10212 xmlXPathCompExprPtr comp;
10213 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010214 xmlNodePtr bak;
10215 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010216 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010217 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010218
Daniel Veillard556c6682001-10-06 09:59:51 +000010219 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010220 comp = ctxt->comp;
10221 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010222 case XPATH_OP_END:
10223 return (0);
10224 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010225 bakd = ctxt->context->doc;
10226 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010227 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010228 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010229 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010230 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010231 xmlXPathBooleanFunction(ctxt, 1);
10232 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10233 return (total);
10234 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010235 ctxt->context->doc = bakd;
10236 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010237 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010238 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010239 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010240 if (ctxt->error) {
10241 xmlXPathFreeObject(arg2);
10242 return(0);
10243 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010244 xmlXPathBooleanFunction(ctxt, 1);
10245 arg1 = valuePop(ctxt);
10246 arg1->boolval &= arg2->boolval;
10247 valuePush(ctxt, arg1);
10248 xmlXPathFreeObject(arg2);
10249 return (total);
10250 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010251 bakd = ctxt->context->doc;
10252 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010253 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010254 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010255 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010256 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010257 xmlXPathBooleanFunction(ctxt, 1);
10258 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10259 return (total);
10260 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010261 ctxt->context->doc = bakd;
10262 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010263 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010264 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010265 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010266 if (ctxt->error) {
10267 xmlXPathFreeObject(arg2);
10268 return(0);
10269 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010270 xmlXPathBooleanFunction(ctxt, 1);
10271 arg1 = valuePop(ctxt);
10272 arg1->boolval |= arg2->boolval;
10273 valuePush(ctxt, arg1);
10274 xmlXPathFreeObject(arg2);
10275 return (total);
10276 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010277 bakd = ctxt->context->doc;
10278 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010279 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010280 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010281 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010282 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010283 ctxt->context->doc = bakd;
10284 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010285 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010286 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010287 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010288 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010289 if (op->value)
10290 equal = xmlXPathEqualValues(ctxt);
10291 else
10292 equal = xmlXPathNotEqualValues(ctxt);
10293 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010294 return (total);
10295 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010296 bakd = ctxt->context->doc;
10297 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010298 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010299 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010300 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010301 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010302 ctxt->context->doc = bakd;
10303 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010304 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010305 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010306 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010307 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010308 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10309 valuePush(ctxt, xmlXPathNewBoolean(ret));
10310 return (total);
10311 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010312 bakd = ctxt->context->doc;
10313 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010314 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010315 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010316 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010317 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010318 if (op->ch2 != -1) {
10319 ctxt->context->doc = bakd;
10320 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010321 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010322 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010323 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010324 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010325 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010326 if (op->value == 0)
10327 xmlXPathSubValues(ctxt);
10328 else if (op->value == 1)
10329 xmlXPathAddValues(ctxt);
10330 else if (op->value == 2)
10331 xmlXPathValueFlipSign(ctxt);
10332 else if (op->value == 3) {
10333 CAST_TO_NUMBER;
10334 CHECK_TYPE0(XPATH_NUMBER);
10335 }
10336 return (total);
10337 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010338 bakd = ctxt->context->doc;
10339 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010340 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010341 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010342 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010343 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010344 ctxt->context->doc = bakd;
10345 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010346 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010347 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010348 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010349 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010350 if (op->value == 0)
10351 xmlXPathMultValues(ctxt);
10352 else if (op->value == 1)
10353 xmlXPathDivValues(ctxt);
10354 else if (op->value == 2)
10355 xmlXPathModValues(ctxt);
10356 return (total);
10357 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010358 bakd = ctxt->context->doc;
10359 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010360 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010361 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010362 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010363 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010364 ctxt->context->doc = bakd;
10365 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010366 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010367 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010368 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010369 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010370 CHECK_TYPE0(XPATH_NODESET);
10371 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010372
Daniel Veillardf06307e2001-07-03 10:35:50 +000010373 CHECK_TYPE0(XPATH_NODESET);
10374 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010375
Daniel Veillardf06307e2001-07-03 10:35:50 +000010376 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10377 arg2->nodesetval);
10378 valuePush(ctxt, arg1);
10379 xmlXPathFreeObject(arg2);
10380 return (total);
10381 case XPATH_OP_ROOT:
10382 xmlXPathRoot(ctxt);
10383 return (total);
10384 case XPATH_OP_NODE:
10385 if (op->ch1 != -1)
10386 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010387 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010388 if (op->ch2 != -1)
10389 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010390 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010391 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10392 return (total);
10393 case XPATH_OP_RESET:
10394 if (op->ch1 != -1)
10395 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010396 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010397 if (op->ch2 != -1)
10398 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010399 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010400 ctxt->context->node = NULL;
10401 return (total);
10402 case XPATH_OP_COLLECT:{
10403 if (op->ch1 == -1)
10404 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010405
Daniel Veillardf06307e2001-07-03 10:35:50 +000010406 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010407 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010408
Daniel Veillardf06307e2001-07-03 10:35:50 +000010409 /*
10410 * Optimization for [n] selection where n is a number
10411 */
10412 if ((op->ch2 != -1) &&
10413 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10414 (comp->steps[op->ch2].ch1 == -1) &&
10415 (comp->steps[op->ch2].ch2 != -1) &&
10416 (comp->steps[comp->steps[op->ch2].ch2].op ==
10417 XPATH_OP_VALUE)) {
10418 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010419
Daniel Veillardf06307e2001-07-03 10:35:50 +000010420 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10421 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10422 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010423
Daniel Veillardf06307e2001-07-03 10:35:50 +000010424 if (val->floatval == (float) indx) {
10425 total +=
10426 xmlXPathNodeCollectAndTestNth(ctxt, op,
10427 indx, NULL,
10428 NULL);
10429 return (total);
10430 }
10431 }
10432 }
10433 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10434 return (total);
10435 }
10436 case XPATH_OP_VALUE:
10437 valuePush(ctxt,
10438 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10439 return (total);
10440 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010441 xmlXPathObjectPtr val;
10442
Daniel Veillardf06307e2001-07-03 10:35:50 +000010443 if (op->ch1 != -1)
10444 total +=
10445 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010446 if (op->value5 == NULL) {
10447 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10448 if (val == NULL) {
10449 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10450 return(0);
10451 }
10452 valuePush(ctxt, val);
10453 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010454 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010455
Daniel Veillardf06307e2001-07-03 10:35:50 +000010456 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10457 if (URI == NULL) {
10458 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010459 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010460 op->value4, op->value5);
10461 return (total);
10462 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010463 val = xmlXPathVariableLookupNS(ctxt->context,
10464 op->value4, URI);
10465 if (val == NULL) {
10466 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10467 return(0);
10468 }
10469 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010470 }
10471 return (total);
10472 }
10473 case XPATH_OP_FUNCTION:{
10474 xmlXPathFunction func;
10475 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010476 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010477
10478 if (op->ch1 != -1)
10479 total +=
10480 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010481 if (ctxt->valueNr < op->value) {
10482 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010483 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010484 ctxt->error = XPATH_INVALID_OPERAND;
10485 return (total);
10486 }
10487 for (i = 0; i < op->value; i++)
10488 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10489 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010490 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010491 ctxt->error = XPATH_INVALID_OPERAND;
10492 return (total);
10493 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010494 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000010495 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010496 else {
10497 const xmlChar *URI = NULL;
10498
10499 if (op->value5 == NULL)
10500 func =
10501 xmlXPathFunctionLookup(ctxt->context,
10502 op->value4);
10503 else {
10504 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10505 if (URI == NULL) {
10506 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010507 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010508 op->value4, op->value5);
10509 return (total);
10510 }
10511 func = xmlXPathFunctionLookupNS(ctxt->context,
10512 op->value4, URI);
10513 }
10514 if (func == NULL) {
10515 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010516 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010517 op->value4);
10518 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010519 }
William M. Brackad0e67c2004-12-01 14:35:10 +000010520 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010521 op->cacheURI = (void *) URI;
10522 }
10523 oldFunc = ctxt->context->function;
10524 oldFuncURI = ctxt->context->functionURI;
10525 ctxt->context->function = op->value4;
10526 ctxt->context->functionURI = op->cacheURI;
10527 func(ctxt, op->value);
10528 ctxt->context->function = oldFunc;
10529 ctxt->context->functionURI = oldFuncURI;
10530 return (total);
10531 }
10532 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010533 bakd = ctxt->context->doc;
10534 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000010535 pp = ctxt->context->proximityPosition;
10536 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010537 if (op->ch1 != -1)
10538 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000010539 ctxt->context->contextSize = cs;
10540 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000010541 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000010542 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000010543 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010544 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010545 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010546 ctxt->context->doc = bakd;
10547 ctxt->context->node = bak;
10548 CHECK_ERROR0;
10549 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010550 return (total);
10551 case XPATH_OP_PREDICATE:
10552 case XPATH_OP_FILTER:{
10553 xmlXPathObjectPtr res;
10554 xmlXPathObjectPtr obj, tmp;
10555 xmlNodeSetPtr newset = NULL;
10556 xmlNodeSetPtr oldset;
10557 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000010558 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010559 int i;
10560
10561 /*
10562 * Optimization for ()[1] selection i.e. the first elem
10563 */
10564 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10565 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10566 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10567 xmlXPathObjectPtr val;
10568
10569 val = comp->steps[op->ch2].value4;
10570 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10571 (val->floatval == 1.0)) {
10572 xmlNodePtr first = NULL;
10573
10574 total +=
10575 xmlXPathCompOpEvalFirst(ctxt,
10576 &comp->steps[op->ch1],
10577 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010578 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010579 /*
10580 * The nodeset should be in document order,
10581 * Keep only the first value
10582 */
10583 if ((ctxt->value != NULL) &&
10584 (ctxt->value->type == XPATH_NODESET) &&
10585 (ctxt->value->nodesetval != NULL) &&
10586 (ctxt->value->nodesetval->nodeNr > 1))
10587 ctxt->value->nodesetval->nodeNr = 1;
10588 return (total);
10589 }
10590 }
10591 /*
10592 * Optimization for ()[last()] selection i.e. the last elem
10593 */
10594 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10595 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10596 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10597 int f = comp->steps[op->ch2].ch1;
10598
10599 if ((f != -1) &&
10600 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10601 (comp->steps[f].value5 == NULL) &&
10602 (comp->steps[f].value == 0) &&
10603 (comp->steps[f].value4 != NULL) &&
10604 (xmlStrEqual
10605 (comp->steps[f].value4, BAD_CAST "last"))) {
10606 xmlNodePtr last = NULL;
10607
10608 total +=
10609 xmlXPathCompOpEvalLast(ctxt,
10610 &comp->steps[op->ch1],
10611 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010612 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010613 /*
10614 * The nodeset should be in document order,
10615 * Keep only the last value
10616 */
10617 if ((ctxt->value != NULL) &&
10618 (ctxt->value->type == XPATH_NODESET) &&
10619 (ctxt->value->nodesetval != NULL) &&
10620 (ctxt->value->nodesetval->nodeTab != NULL) &&
10621 (ctxt->value->nodesetval->nodeNr > 1)) {
10622 ctxt->value->nodesetval->nodeTab[0] =
10623 ctxt->value->nodesetval->nodeTab[ctxt->
10624 value->
10625 nodesetval->
10626 nodeNr -
10627 1];
10628 ctxt->value->nodesetval->nodeNr = 1;
10629 }
10630 return (total);
10631 }
10632 }
10633
10634 if (op->ch1 != -1)
10635 total +=
10636 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010637 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010638 if (op->ch2 == -1)
10639 return (total);
10640 if (ctxt->value == NULL)
10641 return (total);
10642
10643 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010644
10645#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010646 /*
10647 * Hum are we filtering the result of an XPointer expression
10648 */
10649 if (ctxt->value->type == XPATH_LOCATIONSET) {
10650 xmlLocationSetPtr newlocset = NULL;
10651 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010652
Daniel Veillardf06307e2001-07-03 10:35:50 +000010653 /*
10654 * Extract the old locset, and then evaluate the result of the
10655 * expression for all the element in the locset. use it to grow
10656 * up a new locset.
10657 */
10658 CHECK_TYPE0(XPATH_LOCATIONSET);
10659 obj = valuePop(ctxt);
10660 oldlocset = obj->user;
10661 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010662
Daniel Veillardf06307e2001-07-03 10:35:50 +000010663 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10664 ctxt->context->contextSize = 0;
10665 ctxt->context->proximityPosition = 0;
10666 if (op->ch2 != -1)
10667 total +=
10668 xmlXPathCompOpEval(ctxt,
10669 &comp->steps[op->ch2]);
10670 res = valuePop(ctxt);
10671 if (res != NULL)
10672 xmlXPathFreeObject(res);
10673 valuePush(ctxt, obj);
10674 CHECK_ERROR0;
10675 return (total);
10676 }
10677 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010678
Daniel Veillardf06307e2001-07-03 10:35:50 +000010679 for (i = 0; i < oldlocset->locNr; i++) {
10680 /*
10681 * Run the evaluation with a node list made of a
10682 * single item in the nodelocset.
10683 */
10684 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010685 ctxt->context->contextSize = oldlocset->locNr;
10686 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010687 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10688 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010689
Daniel Veillardf06307e2001-07-03 10:35:50 +000010690 if (op->ch2 != -1)
10691 total +=
10692 xmlXPathCompOpEval(ctxt,
10693 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010694 if (ctxt->error != XPATH_EXPRESSION_OK) {
10695 xmlXPathFreeObject(obj);
10696 return(0);
10697 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010698
Daniel Veillardf06307e2001-07-03 10:35:50 +000010699 /*
10700 * The result of the evaluation need to be tested to
10701 * decided whether the filter succeeded or not
10702 */
10703 res = valuePop(ctxt);
10704 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10705 xmlXPtrLocationSetAdd(newlocset,
10706 xmlXPathObjectCopy
10707 (oldlocset->locTab[i]));
10708 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010709
Daniel Veillardf06307e2001-07-03 10:35:50 +000010710 /*
10711 * Cleanup
10712 */
10713 if (res != NULL)
10714 xmlXPathFreeObject(res);
10715 if (ctxt->value == tmp) {
10716 res = valuePop(ctxt);
10717 xmlXPathFreeObject(res);
10718 }
10719
10720 ctxt->context->node = NULL;
10721 }
10722
10723 /*
10724 * The result is used as the new evaluation locset.
10725 */
10726 xmlXPathFreeObject(obj);
10727 ctxt->context->node = NULL;
10728 ctxt->context->contextSize = -1;
10729 ctxt->context->proximityPosition = -1;
10730 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10731 ctxt->context->node = oldnode;
10732 return (total);
10733 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010734#endif /* LIBXML_XPTR_ENABLED */
10735
Daniel Veillardf06307e2001-07-03 10:35:50 +000010736 /*
10737 * Extract the old set, and then evaluate the result of the
10738 * expression for all the element in the set. use it to grow
10739 * up a new set.
10740 */
10741 CHECK_TYPE0(XPATH_NODESET);
10742 obj = valuePop(ctxt);
10743 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010744
Daniel Veillardf06307e2001-07-03 10:35:50 +000010745 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000010746 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010747 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010748
Daniel Veillardf06307e2001-07-03 10:35:50 +000010749 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10750 ctxt->context->contextSize = 0;
10751 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000010752/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000010753 if (op->ch2 != -1)
10754 total +=
10755 xmlXPathCompOpEval(ctxt,
10756 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010757 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010758 res = valuePop(ctxt);
10759 if (res != NULL)
10760 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000010761*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000010762 valuePush(ctxt, obj);
10763 ctxt->context->node = oldnode;
10764 CHECK_ERROR0;
10765 } else {
10766 /*
10767 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000010768 * Also set the xpath document in case things like
10769 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000010770 */
10771 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010772
Daniel Veillardf06307e2001-07-03 10:35:50 +000010773 for (i = 0; i < oldset->nodeNr; i++) {
10774 /*
10775 * Run the evaluation with a node list made of
10776 * a single item in the nodeset.
10777 */
10778 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000010779 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
10780 (oldset->nodeTab[i]->doc != NULL))
10781 ctxt->context->doc = oldset->nodeTab[i]->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010782 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10783 valuePush(ctxt, tmp);
10784 ctxt->context->contextSize = oldset->nodeNr;
10785 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010786
Daniel Veillardf06307e2001-07-03 10:35:50 +000010787 if (op->ch2 != -1)
10788 total +=
10789 xmlXPathCompOpEval(ctxt,
10790 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010791 if (ctxt->error != XPATH_EXPRESSION_OK) {
10792 xmlXPathFreeNodeSet(newset);
10793 xmlXPathFreeObject(obj);
10794 return(0);
10795 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010796
Daniel Veillardf06307e2001-07-03 10:35:50 +000010797 /*
William M. Brack08171912003-12-29 02:52:11 +000010798 * The result of the evaluation needs to be tested to
10799 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010800 */
10801 res = valuePop(ctxt);
10802 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10803 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10804 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010805
Daniel Veillardf06307e2001-07-03 10:35:50 +000010806 /*
10807 * Cleanup
10808 */
10809 if (res != NULL)
10810 xmlXPathFreeObject(res);
10811 if (ctxt->value == tmp) {
10812 res = valuePop(ctxt);
10813 xmlXPathFreeObject(res);
10814 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010815
Daniel Veillardf06307e2001-07-03 10:35:50 +000010816 ctxt->context->node = NULL;
10817 }
10818
10819 /*
10820 * The result is used as the new evaluation set.
10821 */
10822 xmlXPathFreeObject(obj);
10823 ctxt->context->node = NULL;
10824 ctxt->context->contextSize = -1;
10825 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000010826 /* may want to move this past the '}' later */
10827 ctxt->context->doc = oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010828 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10829 }
10830 ctxt->context->node = oldnode;
10831 return (total);
10832 }
10833 case XPATH_OP_SORT:
10834 if (op->ch1 != -1)
10835 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010836 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010837 if ((ctxt->value != NULL) &&
10838 (ctxt->value->type == XPATH_NODESET) &&
10839 (ctxt->value->nodesetval != NULL))
10840 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10841 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010842#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010843 case XPATH_OP_RANGETO:{
10844 xmlXPathObjectPtr range;
10845 xmlXPathObjectPtr res, obj;
10846 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010847 xmlLocationSetPtr newlocset = NULL;
10848 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010849 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000010850 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010851
Daniel Veillardf06307e2001-07-03 10:35:50 +000010852 if (op->ch1 != -1)
10853 total +=
10854 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10855 if (op->ch2 == -1)
10856 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010857
William M. Brack08171912003-12-29 02:52:11 +000010858 if (ctxt->value->type == XPATH_LOCATIONSET) {
10859 /*
10860 * Extract the old locset, and then evaluate the result of the
10861 * expression for all the element in the locset. use it to grow
10862 * up a new locset.
10863 */
10864 CHECK_TYPE0(XPATH_LOCATIONSET);
10865 obj = valuePop(ctxt);
10866 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010867
William M. Brack08171912003-12-29 02:52:11 +000010868 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000010869 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000010870 ctxt->context->contextSize = 0;
10871 ctxt->context->proximityPosition = 0;
10872 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10873 res = valuePop(ctxt);
10874 if (res != NULL)
10875 xmlXPathFreeObject(res);
10876 valuePush(ctxt, obj);
10877 CHECK_ERROR0;
10878 return (total);
10879 }
10880 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010881
William M. Brack08171912003-12-29 02:52:11 +000010882 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010883 /*
William M. Brack08171912003-12-29 02:52:11 +000010884 * Run the evaluation with a node list made of a
10885 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010886 */
William M. Brackf7eb7942003-12-31 07:59:17 +000010887 ctxt->context->node = oldlocset->locTab[i]->user;
10888 ctxt->context->contextSize = oldlocset->locNr;
10889 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010890 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10891 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010892
Daniel Veillardf06307e2001-07-03 10:35:50 +000010893 if (op->ch2 != -1)
10894 total +=
10895 xmlXPathCompOpEval(ctxt,
10896 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010897 if (ctxt->error != XPATH_EXPRESSION_OK) {
10898 xmlXPathFreeObject(obj);
10899 return(0);
10900 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010901
Daniel Veillardf06307e2001-07-03 10:35:50 +000010902 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000010903 if (res->type == XPATH_LOCATIONSET) {
10904 xmlLocationSetPtr rloc =
10905 (xmlLocationSetPtr)res->user;
10906 for (j=0; j<rloc->locNr; j++) {
10907 range = xmlXPtrNewRange(
10908 oldlocset->locTab[i]->user,
10909 oldlocset->locTab[i]->index,
10910 rloc->locTab[j]->user2,
10911 rloc->locTab[j]->index2);
10912 if (range != NULL) {
10913 xmlXPtrLocationSetAdd(newlocset, range);
10914 }
10915 }
10916 } else {
10917 range = xmlXPtrNewRangeNodeObject(
10918 (xmlNodePtr)oldlocset->locTab[i]->user, res);
10919 if (range != NULL) {
10920 xmlXPtrLocationSetAdd(newlocset,range);
10921 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010922 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010923
Daniel Veillardf06307e2001-07-03 10:35:50 +000010924 /*
10925 * Cleanup
10926 */
10927 if (res != NULL)
10928 xmlXPathFreeObject(res);
10929 if (ctxt->value == tmp) {
10930 res = valuePop(ctxt);
10931 xmlXPathFreeObject(res);
10932 }
10933
10934 ctxt->context->node = NULL;
10935 }
William M. Brack72ee48d2003-12-30 08:30:19 +000010936 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000010937 CHECK_TYPE0(XPATH_NODESET);
10938 obj = valuePop(ctxt);
10939 oldset = obj->nodesetval;
10940 ctxt->context->node = NULL;
10941
10942 newlocset = xmlXPtrLocationSetCreate(NULL);
10943
10944 if (oldset != NULL) {
10945 for (i = 0; i < oldset->nodeNr; i++) {
10946 /*
10947 * Run the evaluation with a node list made of a single item
10948 * in the nodeset.
10949 */
10950 ctxt->context->node = oldset->nodeTab[i];
10951 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10952 valuePush(ctxt, tmp);
10953
10954 if (op->ch2 != -1)
10955 total +=
10956 xmlXPathCompOpEval(ctxt,
10957 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010958 if (ctxt->error != XPATH_EXPRESSION_OK) {
10959 xmlXPathFreeObject(obj);
10960 return(0);
10961 }
William M. Brack08171912003-12-29 02:52:11 +000010962
William M. Brack08171912003-12-29 02:52:11 +000010963 res = valuePop(ctxt);
10964 range =
10965 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10966 res);
10967 if (range != NULL) {
10968 xmlXPtrLocationSetAdd(newlocset, range);
10969 }
10970
10971 /*
10972 * Cleanup
10973 */
10974 if (res != NULL)
10975 xmlXPathFreeObject(res);
10976 if (ctxt->value == tmp) {
10977 res = valuePop(ctxt);
10978 xmlXPathFreeObject(res);
10979 }
10980
10981 ctxt->context->node = NULL;
10982 }
10983 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010984 }
10985
10986 /*
10987 * The result is used as the new evaluation set.
10988 */
10989 xmlXPathFreeObject(obj);
10990 ctxt->context->node = NULL;
10991 ctxt->context->contextSize = -1;
10992 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010993 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010994 return (total);
10995 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010996#endif /* LIBXML_XPTR_ENABLED */
10997 }
10998 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010999 "XPath: unknown precompiled operation %d\n", op->op);
11000 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011001}
11002
Daniel Veillard56de87e2005-02-16 00:22:29 +000011003#ifdef XPATH_STREAMING
11004/**
11005 * xmlXPathRunStreamEval:
11006 * @ctxt: the XPath parser context with the compiled expression
11007 *
11008 * Evaluate the Precompiled Streamable XPath expression in the given context.
11009 */
11010static xmlXPathObjectPtr
11011xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp) {
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011012 int max_depth, min_depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011013 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011014 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011015#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11016 int eval_all_nodes;
11017#endif
William M. Brack12d37ab2005-02-21 13:54:07 +000011018 xmlNodePtr cur = NULL, limit = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011019 xmlXPathObjectPtr retval;
11020 xmlStreamCtxtPtr patstream;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011021
11022 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011023
11024 if ((ctxt == NULL) || (comp == NULL))
11025 return(NULL);
11026 max_depth = xmlPatternMaxDepth(comp);
11027 if (max_depth == -1)
11028 return(NULL);
11029 if (max_depth == -2)
11030 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011031 min_depth = xmlPatternMinDepth(comp);
11032 if (min_depth == -1)
11033 return(NULL);
Daniel Veillard56de87e2005-02-16 00:22:29 +000011034 from_root = xmlPatternFromRoot(comp);
11035 if (from_root < 0)
11036 return(NULL);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000011037#if 0
11038 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
11039#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011040
11041 retval = xmlXPathNewNodeSet(NULL);
11042 if (retval == NULL)
11043 return(NULL);
11044
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011045 /*
11046 * handle the special cases of / amd . being matched
11047 */
11048 if (min_depth == 0) {
11049 if (from_root) {
11050 xmlXPathNodeSetAddUnique(retval->nodesetval, (xmlNodePtr) ctxt->doc);
11051 } else {
11052 xmlXPathNodeSetAddUnique(retval->nodesetval, ctxt->node);
11053 }
11054 }
11055 if (max_depth == 0) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011056 return(retval);
11057 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011058
Daniel Veillard56de87e2005-02-16 00:22:29 +000011059 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000011060 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011061 } else if (ctxt->node != NULL) {
11062 switch (ctxt->node->type) {
11063 case XML_ELEMENT_NODE:
11064 case XML_DOCUMENT_NODE:
11065 case XML_DOCUMENT_FRAG_NODE:
11066 case XML_HTML_DOCUMENT_NODE:
11067#ifdef LIBXML_DOCB_ENABLED
11068 case XML_DOCB_DOCUMENT_NODE:
11069#endif
11070 cur = ctxt->node;
11071 break;
11072 case XML_ATTRIBUTE_NODE:
11073 case XML_TEXT_NODE:
11074 case XML_CDATA_SECTION_NODE:
11075 case XML_ENTITY_REF_NODE:
11076 case XML_ENTITY_NODE:
11077 case XML_PI_NODE:
11078 case XML_COMMENT_NODE:
11079 case XML_NOTATION_NODE:
11080 case XML_DTD_NODE:
11081 case XML_DOCUMENT_TYPE_NODE:
11082 case XML_ELEMENT_DECL:
11083 case XML_ATTRIBUTE_DECL:
11084 case XML_ENTITY_DECL:
11085 case XML_NAMESPACE_DECL:
11086 case XML_XINCLUDE_START:
11087 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000011088 break;
11089 }
11090 limit = cur;
11091 }
11092 if (cur == NULL)
11093 return(retval);
11094
11095 patstream = xmlPatternGetStreamCtxt(comp);
11096 if (patstream == NULL) {
11097 return(retval);
11098 }
11099
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011100#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11101 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
11102#endif
11103
Daniel Veillard56de87e2005-02-16 00:22:29 +000011104 if (from_root) {
11105 ret = xmlStreamPush(patstream, NULL, NULL);
11106 if (ret < 0) {
11107 } else if (ret == 1) {
11108 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11109 }
11110 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011111 depth = 0;
11112 goto scan_children;
11113 do {
11114next_node:
11115 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011116
11117 switch (cur->type) {
11118 case XML_ELEMENT_NODE:
11119#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11120 case XML_TEXT_NODE:
11121 case XML_CDATA_SECTION_NODE:
11122 case XML_COMMENT_NODE:
11123 case XML_PI_NODE:
11124#endif
11125 if (cur->type == XML_ELEMENT_NODE) {
11126 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000011127 (cur->ns ? cur->ns->href : NULL));
William M. Brackfbb619f2005-06-06 13:49:18 +000011128 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011129#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11130 else if (eval_all_nodes)
11131 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
11132 else
11133 break;
11134#endif
11135
11136 if (ret < 0) {
11137 /* NOP. */
11138 } else if (ret == 1) {
11139 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11140 }
11141 if ((cur->children == NULL) || (depth >= max_depth)) {
11142 ret = xmlStreamPop(patstream);
11143 while (cur->next != NULL) {
11144 cur = cur->next;
11145 if ((cur->type != XML_ENTITY_DECL) &&
11146 (cur->type != XML_DTD_NODE))
11147 goto next_node;
11148 }
11149 }
11150 default:
11151 break;
11152 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011153
11154scan_children:
11155 if ((cur->children != NULL) && (depth < max_depth)) {
11156 /*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011157 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000011158 */
11159 if (cur->children->type != XML_ENTITY_DECL) {
11160 cur = cur->children;
11161 depth++;
11162 /*
11163 * Skip DTDs
11164 */
11165 if (cur->type != XML_DTD_NODE)
11166 continue;
11167 }
11168 }
11169
11170 if (cur == limit)
11171 break;
11172
11173 while (cur->next != NULL) {
11174 cur = cur->next;
11175 if ((cur->type != XML_ENTITY_DECL) &&
11176 (cur->type != XML_DTD_NODE))
11177 goto next_node;
11178 }
11179
11180 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011181 cur = cur->parent;
11182 depth--;
11183 if ((cur == NULL) || (cur == limit))
11184 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011185 if (cur->type == XML_ELEMENT_NODE) {
11186 ret = xmlStreamPop(patstream);
11187 }
11188#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11189 else if ((eval_all_nodes) &&
11190 ((cur->type == XML_TEXT_NODE) ||
11191 (cur->type == XML_CDATA_SECTION_NODE) ||
11192 (cur->type == XML_COMMENT_NODE) ||
11193 (cur->type == XML_PI_NODE)))
11194 {
11195 ret = xmlStreamPop(patstream);
11196 }
11197#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011198 if (cur->next != NULL) {
11199 cur = cur->next;
11200 break;
11201 }
11202 } while (cur != NULL);
11203
11204 } while ((cur != NULL) && (depth >= 0));
11205done:
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000011206#if 0
11207 printf("stream eval: checked %d nodes selected %d\n",
11208 nb_nodes, retval->nodesetval->nodeNr);
11209#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011210 xmlFreeStreamCtxt(patstream);
11211 return(retval);
11212}
11213#endif /* XPATH_STREAMING */
11214
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011215/**
11216 * xmlXPathRunEval:
11217 * @ctxt: the XPath parser context with the compiled expression
11218 *
11219 * Evaluate the Precompiled XPath expression in the given context.
11220 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011221static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011222xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
11223 xmlXPathCompExprPtr comp;
11224
11225 if ((ctxt == NULL) || (ctxt->comp == NULL))
11226 return;
11227
11228 if (ctxt->valueTab == NULL) {
11229 /* Allocate the value stack */
11230 ctxt->valueTab = (xmlXPathObjectPtr *)
11231 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
11232 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000011233 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011234 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011235 }
11236 ctxt->valueNr = 0;
11237 ctxt->valueMax = 10;
11238 ctxt->value = NULL;
11239 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011240#ifdef XPATH_STREAMING
11241 if (ctxt->comp->stream) {
11242 xmlXPathObjectPtr ret;
11243 ret = xmlXPathRunStreamEval(ctxt->context, ctxt->comp->stream);
11244 if (ret != NULL) {
11245 valuePush(ctxt, ret);
11246 return;
11247 }
11248 }
11249#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011250 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000011251 if(comp->last < 0) {
11252 xmlGenericError(xmlGenericErrorContext,
11253 "xmlXPathRunEval: last is less than zero\n");
11254 return;
11255 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011256 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11257}
11258
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011259/************************************************************************
11260 * *
11261 * Public interfaces *
11262 * *
11263 ************************************************************************/
11264
11265/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011266 * xmlXPathEvalPredicate:
11267 * @ctxt: the XPath context
11268 * @res: the Predicate Expression evaluation result
11269 *
11270 * Evaluate a predicate result for the current node.
11271 * A PredicateExpr is evaluated by evaluating the Expr and converting
11272 * the result to a boolean. If the result is a number, the result will
11273 * be converted to true if the number is equal to the position of the
11274 * context node in the context node list (as returned by the position
11275 * function) and will be converted to false otherwise; if the result
11276 * is not a number, then the result will be converted as if by a call
11277 * to the boolean function.
11278 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011279 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011280 */
11281int
11282xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000011283 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011284 switch (res->type) {
11285 case XPATH_BOOLEAN:
11286 return(res->boolval);
11287 case XPATH_NUMBER:
11288 return(res->floatval == ctxt->proximityPosition);
11289 case XPATH_NODESET:
11290 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011291 if (res->nodesetval == NULL)
11292 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011293 return(res->nodesetval->nodeNr != 0);
11294 case XPATH_STRING:
11295 return((res->stringval != NULL) &&
11296 (xmlStrlen(res->stringval) != 0));
11297 default:
11298 STRANGE
11299 }
11300 return(0);
11301}
11302
11303/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011304 * xmlXPathEvaluatePredicateResult:
11305 * @ctxt: the XPath Parser context
11306 * @res: the Predicate Expression evaluation result
11307 *
11308 * Evaluate a predicate result for the current node.
11309 * A PredicateExpr is evaluated by evaluating the Expr and converting
11310 * the result to a boolean. If the result is a number, the result will
11311 * be converted to true if the number is equal to the position of the
11312 * context node in the context node list (as returned by the position
11313 * function) and will be converted to false otherwise; if the result
11314 * is not a number, then the result will be converted as if by a call
11315 * to the boolean function.
11316 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011317 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011318 */
11319int
11320xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
11321 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000011322 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011323 switch (res->type) {
11324 case XPATH_BOOLEAN:
11325 return(res->boolval);
11326 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000011327#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000011328 return((res->floatval == ctxt->context->proximityPosition) &&
11329 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000011330#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011331 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000011332#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011333 case XPATH_NODESET:
11334 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000011335 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000011336 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011337 return(res->nodesetval->nodeNr != 0);
11338 case XPATH_STRING:
11339 return((res->stringval != NULL) &&
11340 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000011341#ifdef LIBXML_XPTR_ENABLED
11342 case XPATH_LOCATIONSET:{
11343 xmlLocationSetPtr ptr = res->user;
11344 if (ptr == NULL)
11345 return(0);
11346 return (ptr->locNr != 0);
11347 }
11348#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011349 default:
11350 STRANGE
11351 }
11352 return(0);
11353}
11354
Daniel Veillard56de87e2005-02-16 00:22:29 +000011355#ifdef XPATH_STREAMING
11356/**
11357 * xmlXPathTryStreamCompile:
11358 * @ctxt: an XPath context
11359 * @str: the XPath expression
11360 *
11361 * Try to compile the XPath expression as a streamable subset.
11362 *
11363 * Returns the compiled expression or NULL if failed to compile.
11364 */
11365static xmlXPathCompExprPtr
11366xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11367 /*
11368 * Optimization: use streaming patterns when the XPath expression can
11369 * be compiled to a stream lookup
11370 */
11371 xmlPatternPtr stream;
11372 xmlXPathCompExprPtr comp;
11373 xmlDictPtr dict = NULL;
11374 const xmlChar **namespaces = NULL;
11375 xmlNsPtr ns;
11376 int i, j;
11377
11378 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
11379 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000011380 const xmlChar *tmp;
11381
11382 /*
11383 * We don't try to handle :: constructs, just the simplied form at
11384 * this point
11385 */
11386 tmp = xmlStrchr(str, ':');
11387 if ((tmp != NULL) && (tmp[1] == ':'))
11388 return(NULL);
11389
Daniel Veillard56de87e2005-02-16 00:22:29 +000011390 if (ctxt != NULL) {
11391 dict = ctxt->dict;
11392 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000011393 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000011394 if (namespaces == NULL) {
11395 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
11396 return(NULL);
11397 }
11398 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
11399 ns = ctxt->namespaces[j];
11400 namespaces[i++] = ns->href;
11401 namespaces[i++] = ns->prefix;
11402 }
11403 namespaces[i++] = NULL;
11404 namespaces[i++] = NULL;
11405 }
11406 }
11407
William M. Brackea152c02005-06-09 18:12:28 +000011408 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
11409 &namespaces[0]);
Daniel Veillard56de87e2005-02-16 00:22:29 +000011410 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
11411 comp = xmlXPathNewCompExpr();
11412 if (comp == NULL) {
11413 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
11414 return(NULL);
11415 }
11416 comp->stream = stream;
11417 comp->dict = dict;
11418 if (comp->dict)
11419 xmlDictReference(comp->dict);
11420 return(comp);
11421 }
11422 xmlFreePattern(stream);
11423 }
11424 return(NULL);
11425}
11426#endif /* XPATH_STREAMING */
11427
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011428/**
Daniel Veillard4773df22004-01-23 13:15:13 +000011429 * xmlXPathCtxtCompile:
11430 * @ctxt: an XPath context
11431 * @str: the XPath expression
11432 *
11433 * Compile an XPath expression
11434 *
11435 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
11436 * the caller has to free the object.
11437 */
11438xmlXPathCompExprPtr
11439xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11440 xmlXPathParserContextPtr pctxt;
11441 xmlXPathCompExprPtr comp;
11442
Daniel Veillard56de87e2005-02-16 00:22:29 +000011443#ifdef XPATH_STREAMING
11444 comp = xmlXPathTryStreamCompile(ctxt, str);
11445 if (comp != NULL)
11446 return(comp);
11447#endif
11448
Daniel Veillard4773df22004-01-23 13:15:13 +000011449 xmlXPathInit();
11450
11451 pctxt = xmlXPathNewParserContext(str, ctxt);
11452 xmlXPathCompileExpr(pctxt);
11453
11454 if( pctxt->error != XPATH_EXPRESSION_OK )
11455 {
11456 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011457 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000011458 }
11459
11460 if (*pctxt->cur != 0) {
11461 /*
11462 * aleksey: in some cases this line prints *second* error message
11463 * (see bug #78858) and probably this should be fixed.
11464 * However, we are not sure that all error messages are printed
11465 * out in other places. It's not critical so we leave it as-is for now
11466 */
11467 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11468 comp = NULL;
11469 } else {
11470 comp = pctxt->comp;
11471 pctxt->comp = NULL;
11472 }
11473 xmlXPathFreeParserContext(pctxt);
11474 if (comp != NULL) {
11475 comp->expr = xmlStrdup(str);
11476#ifdef DEBUG_EVAL_COUNTS
11477 comp->string = xmlStrdup(str);
11478 comp->nb = 0;
11479#endif
11480 }
11481 return(comp);
11482}
11483
11484/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011485 * xmlXPathCompile:
11486 * @str: the XPath expression
11487 *
11488 * Compile an XPath expression
11489 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000011490 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011491 * the caller has to free the object.
11492 */
11493xmlXPathCompExprPtr
11494xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000011495 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011496}
11497
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011498/**
11499 * xmlXPathCompiledEval:
11500 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000011501 * @ctx: the XPath context
11502 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011503 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000011504 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011505 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000011506 * the caller has to free the object.
11507 */
11508xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011509xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000011510 xmlXPathParserContextPtr ctxt;
11511 xmlXPathObjectPtr res, tmp, init = NULL;
11512 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000011513#ifndef LIBXML_THREAD_ENABLED
11514 static int reentance = 0;
11515#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011516
William M. Brackf13f77f2004-11-12 16:03:48 +000011517 CHECK_CTXT(ctx)
11518
11519 if (comp == NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011520 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011521 xmlXPathInit();
11522
Daniel Veillard81463942001-10-16 12:34:39 +000011523#ifndef LIBXML_THREAD_ENABLED
11524 reentance++;
11525 if (reentance > 1)
11526 xmlXPathDisableOptimizer = 1;
11527#endif
11528
Daniel Veillardf06307e2001-07-03 10:35:50 +000011529#ifdef DEBUG_EVAL_COUNTS
11530 comp->nb++;
11531 if ((comp->string != NULL) && (comp->nb > 100)) {
11532 fprintf(stderr, "100 x %s\n", comp->string);
11533 comp->nb = 0;
11534 }
11535#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011536 ctxt = xmlXPathCompParserContext(comp, ctx);
11537 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011538
11539 if (ctxt->value == NULL) {
11540 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011541 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011542 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011543 } else {
11544 res = valuePop(ctxt);
11545 }
11546
Daniel Veillardf06307e2001-07-03 10:35:50 +000011547
Owen Taylor3473f882001-02-23 17:55:21 +000011548 do {
11549 tmp = valuePop(ctxt);
11550 if (tmp != NULL) {
11551 if (tmp != init)
11552 stack++;
11553 xmlXPathFreeObject(tmp);
11554 }
11555 } while (tmp != NULL);
11556 if ((stack != 0) && (res != NULL)) {
11557 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011558 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011559 stack);
11560 }
11561 if (ctxt->error != XPATH_EXPRESSION_OK) {
11562 xmlXPathFreeObject(res);
11563 res = NULL;
11564 }
11565
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011566
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011567 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011568 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011569#ifndef LIBXML_THREAD_ENABLED
11570 reentance--;
11571#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011572 return(res);
11573}
11574
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011575/**
11576 * xmlXPathEvalExpr:
11577 * @ctxt: the XPath Parser context
11578 *
11579 * Parse and evaluate an XPath expression in the given context,
11580 * then push the result on the context stack
11581 */
11582void
11583xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011584#ifdef XPATH_STREAMING
11585 xmlXPathCompExprPtr comp;
11586#endif
11587
Daniel Veillarda82b1822004-11-08 16:24:57 +000011588 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011589
11590#ifdef XPATH_STREAMING
11591 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
11592 if (comp != NULL) {
11593 if (ctxt->comp != NULL)
11594 xmlXPathFreeCompExpr(ctxt->comp);
11595 ctxt->comp = comp;
11596 if (ctxt->cur != NULL)
11597 while (*ctxt->cur != 0) ctxt->cur++;
11598 } else
11599#endif
11600 {
11601 xmlXPathCompileExpr(ctxt);
11602 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011603 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011604 xmlXPathRunEval(ctxt);
11605}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011606
11607/**
11608 * xmlXPathEval:
11609 * @str: the XPath expression
11610 * @ctx: the XPath context
11611 *
11612 * Evaluate the XPath Location Path in the given context.
11613 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011614 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011615 * the caller has to free the object.
11616 */
11617xmlXPathObjectPtr
11618xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11619 xmlXPathParserContextPtr ctxt;
11620 xmlXPathObjectPtr res, tmp, init = NULL;
11621 int stack = 0;
11622
William M. Brackf13f77f2004-11-12 16:03:48 +000011623 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011624
William M. Brackf13f77f2004-11-12 16:03:48 +000011625 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011626
11627 ctxt = xmlXPathNewParserContext(str, ctx);
11628 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011629
11630 if (ctxt->value == NULL) {
11631 xmlGenericError(xmlGenericErrorContext,
11632 "xmlXPathEval: evaluation failed\n");
11633 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011634 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
11635#ifdef XPATH_STREAMING
11636 && (ctxt->comp->stream == NULL)
11637#endif
11638 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011639 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11640 res = NULL;
11641 } else {
11642 res = valuePop(ctxt);
11643 }
11644
11645 do {
11646 tmp = valuePop(ctxt);
11647 if (tmp != NULL) {
11648 if (tmp != init)
11649 stack++;
11650 xmlXPathFreeObject(tmp);
11651 }
11652 } while (tmp != NULL);
11653 if ((stack != 0) && (res != NULL)) {
11654 xmlGenericError(xmlGenericErrorContext,
11655 "xmlXPathEval: %d object left on the stack\n",
11656 stack);
11657 }
11658 if (ctxt->error != XPATH_EXPRESSION_OK) {
11659 xmlXPathFreeObject(res);
11660 res = NULL;
11661 }
11662
Owen Taylor3473f882001-02-23 17:55:21 +000011663 xmlXPathFreeParserContext(ctxt);
11664 return(res);
11665}
11666
11667/**
11668 * xmlXPathEvalExpression:
11669 * @str: the XPath expression
11670 * @ctxt: the XPath context
11671 *
11672 * Evaluate the XPath expression in the given context.
11673 *
11674 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11675 * the caller has to free the object.
11676 */
11677xmlXPathObjectPtr
11678xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11679 xmlXPathParserContextPtr pctxt;
11680 xmlXPathObjectPtr res, tmp;
11681 int stack = 0;
11682
William M. Brackf13f77f2004-11-12 16:03:48 +000011683 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000011684
William M. Brackf13f77f2004-11-12 16:03:48 +000011685 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000011686
11687 pctxt = xmlXPathNewParserContext(str, ctxt);
11688 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011689
11690 if (*pctxt->cur != 0) {
11691 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11692 res = NULL;
11693 } else {
11694 res = valuePop(pctxt);
11695 }
11696 do {
11697 tmp = valuePop(pctxt);
11698 if (tmp != NULL) {
11699 xmlXPathFreeObject(tmp);
11700 stack++;
11701 }
11702 } while (tmp != NULL);
11703 if ((stack != 0) && (res != NULL)) {
11704 xmlGenericError(xmlGenericErrorContext,
11705 "xmlXPathEvalExpression: %d object left on the stack\n",
11706 stack);
11707 }
11708 xmlXPathFreeParserContext(pctxt);
11709 return(res);
11710}
11711
Daniel Veillard42766c02002-08-22 20:52:17 +000011712/************************************************************************
11713 * *
11714 * Extra functions not pertaining to the XPath spec *
11715 * *
11716 ************************************************************************/
11717/**
11718 * xmlXPathEscapeUriFunction:
11719 * @ctxt: the XPath Parser context
11720 * @nargs: the number of arguments
11721 *
11722 * Implement the escape-uri() XPath function
11723 * string escape-uri(string $str, bool $escape-reserved)
11724 *
11725 * This function applies the URI escaping rules defined in section 2 of [RFC
11726 * 2396] to the string supplied as $uri-part, which typically represents all
11727 * or part of a URI. The effect of the function is to replace any special
11728 * character in the string by an escape sequence of the form %xx%yy...,
11729 * where xxyy... is the hexadecimal representation of the octets used to
11730 * represent the character in UTF-8.
11731 *
11732 * The set of characters that are escaped depends on the setting of the
11733 * boolean argument $escape-reserved.
11734 *
11735 * If $escape-reserved is true, all characters are escaped other than lower
11736 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11737 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11738 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11739 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11740 * A-F).
11741 *
11742 * If $escape-reserved is false, the behavior differs in that characters
11743 * referred to in [RFC 2396] as reserved characters are not escaped. These
11744 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11745 *
11746 * [RFC 2396] does not define whether escaped URIs should use lower case or
11747 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11748 * compared using string comparison functions, this function must always use
11749 * the upper-case letters A-F.
11750 *
11751 * Generally, $escape-reserved should be set to true when escaping a string
11752 * that is to form a single part of a URI, and to false when escaping an
11753 * entire URI or URI reference.
11754 *
11755 * In the case of non-ascii characters, the string is encoded according to
11756 * utf-8 and then converted according to RFC 2396.
11757 *
11758 * Examples
11759 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11760 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11761 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11762 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11763 *
11764 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011765static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011766xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11767 xmlXPathObjectPtr str;
11768 int escape_reserved;
11769 xmlBufferPtr target;
11770 xmlChar *cptr;
11771 xmlChar escape[4];
11772
11773 CHECK_ARITY(2);
11774
11775 escape_reserved = xmlXPathPopBoolean(ctxt);
11776
11777 CAST_TO_STRING;
11778 str = valuePop(ctxt);
11779
11780 target = xmlBufferCreate();
11781
11782 escape[0] = '%';
11783 escape[3] = 0;
11784
11785 if (target) {
11786 for (cptr = str->stringval; *cptr; cptr++) {
11787 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11788 (*cptr >= 'a' && *cptr <= 'z') ||
11789 (*cptr >= '0' && *cptr <= '9') ||
11790 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11791 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11792 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11793 (*cptr == '%' &&
11794 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11795 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11796 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11797 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11798 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11799 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11800 (!escape_reserved &&
11801 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11802 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11803 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11804 *cptr == ','))) {
11805 xmlBufferAdd(target, cptr, 1);
11806 } else {
11807 if ((*cptr >> 4) < 10)
11808 escape[1] = '0' + (*cptr >> 4);
11809 else
11810 escape[1] = 'A' - 10 + (*cptr >> 4);
11811 if ((*cptr & 0xF) < 10)
11812 escape[2] = '0' + (*cptr & 0xF);
11813 else
11814 escape[2] = 'A' - 10 + (*cptr & 0xF);
11815
11816 xmlBufferAdd(target, &escape[0], 3);
11817 }
11818 }
11819 }
11820 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11821 xmlBufferFree(target);
11822 xmlXPathFreeObject(str);
11823}
11824
Owen Taylor3473f882001-02-23 17:55:21 +000011825/**
11826 * xmlXPathRegisterAllFunctions:
11827 * @ctxt: the XPath context
11828 *
11829 * Registers all default XPath functions in this context
11830 */
11831void
11832xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11833{
11834 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11835 xmlXPathBooleanFunction);
11836 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11837 xmlXPathCeilingFunction);
11838 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11839 xmlXPathCountFunction);
11840 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11841 xmlXPathConcatFunction);
11842 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11843 xmlXPathContainsFunction);
11844 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11845 xmlXPathIdFunction);
11846 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11847 xmlXPathFalseFunction);
11848 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11849 xmlXPathFloorFunction);
11850 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11851 xmlXPathLastFunction);
11852 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11853 xmlXPathLangFunction);
11854 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11855 xmlXPathLocalNameFunction);
11856 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11857 xmlXPathNotFunction);
11858 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11859 xmlXPathNameFunction);
11860 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11861 xmlXPathNamespaceURIFunction);
11862 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11863 xmlXPathNormalizeFunction);
11864 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11865 xmlXPathNumberFunction);
11866 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11867 xmlXPathPositionFunction);
11868 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11869 xmlXPathRoundFunction);
11870 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11871 xmlXPathStringFunction);
11872 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11873 xmlXPathStringLengthFunction);
11874 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11875 xmlXPathStartsWithFunction);
11876 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11877 xmlXPathSubstringFunction);
11878 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11879 xmlXPathSubstringBeforeFunction);
11880 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11881 xmlXPathSubstringAfterFunction);
11882 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11883 xmlXPathSumFunction);
11884 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11885 xmlXPathTrueFunction);
11886 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11887 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011888
11889 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11890 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11891 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011892}
11893
11894#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000011895#define bottom_xpath
11896#include "elfgcchack.h"