blob: 2ea8c26ac7266a4868c4b95245ed86c75ce36719 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
5 *
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
Owen Taylor3473f882001-02-23 17:55:21 +000031#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000034#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000035#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#endif
Owen Taylor3473f882001-02-23 17:55:21 +000037
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000052#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000053#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000054
Daniel Veillardd96f6d32003-10-07 21:25:12 +000055#define TODO \
56 xmlGenericError(xmlGenericErrorContext, \
57 "Unimplemented block at %s:%d\n", \
58 __FILE__, __LINE__);
59
William M. Brackd1757ab2004-10-02 22:07:48 +000060/*
61 * TODO:
62 * There are a few spots where some tests are done which depend upon ascii
63 * data. These should be enhanced for full UTF8 support (see particularly
64 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
65 */
66
William M. Brack21e4ef22005-01-02 09:53:13 +000067#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000068/************************************************************************
69 * *
70 * Floating point stuff *
71 * *
72 ************************************************************************/
73
Daniel Veillardc0631a62001-09-20 13:56:06 +000074#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000075#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000076#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000077#include "trionan.c"
78
Owen Taylor3473f882001-02-23 17:55:21 +000079/*
Owen Taylor3473f882001-02-23 17:55:21 +000080 * The lack of portability of this section of the libc is annoying !
81 */
82double xmlXPathNAN = 0;
83double xmlXPathPINF = 1;
84double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000085double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000086static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000087
Owen Taylor3473f882001-02-23 17:55:21 +000088/**
89 * xmlXPathInit:
90 *
91 * Initialize the XPath environment
92 */
93void
94xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +000095 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +000096
Bjorn Reese45029602001-08-21 09:23:53 +000097 xmlXPathPINF = trio_pinf();
98 xmlXPathNINF = trio_ninf();
99 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000100 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000101
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000102 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000103}
104
Daniel Veillardcda96922001-08-21 10:56:31 +0000105/**
106 * xmlXPathIsNaN:
107 * @val: a double value
108 *
109 * Provides a portable isnan() function to detect whether a double
110 * is a NotaNumber. Based on trio code
111 * http://sourceforge.net/projects/ctrio/
112 *
113 * Returns 1 if the value is a NaN, 0 otherwise
114 */
115int
116xmlXPathIsNaN(double val) {
117 return(trio_isnan(val));
118}
119
120/**
121 * xmlXPathIsInf:
122 * @val: a double value
123 *
124 * Provides a portable isinf() function to detect whether a double
125 * is a +Infinite or -Infinite. Based on trio code
126 * http://sourceforge.net/projects/ctrio/
127 *
128 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
129 */
130int
131xmlXPathIsInf(double val) {
132 return(trio_isinf(val));
133}
134
Daniel Veillard4432df22003-09-28 18:58:27 +0000135#endif /* SCHEMAS or XPATH */
136#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000137/**
138 * xmlXPathGetSign:
139 * @val: a double value
140 *
141 * Provides a portable function to detect the sign of a double
142 * Modified from trio code
143 * http://sourceforge.net/projects/ctrio/
144 *
145 * Returns 1 if the value is Negative, 0 if positive
146 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000147static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000148xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000149 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000150}
151
152
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000153/*
154 * TODO: when compatibility allows remove all "fake node libxslt" strings
155 * the test should just be name[0] = ' '
156 */
157/* #define DEBUG */
158/* #define DEBUG_STEP */
159/* #define DEBUG_STEP_NTH */
160/* #define DEBUG_EXPR */
161/* #define DEBUG_EVAL_COUNTS */
162
163static xmlNs xmlXPathXMLNamespaceStruct = {
164 NULL,
165 XML_NAMESPACE_DECL,
166 XML_XML_NAMESPACE,
167 BAD_CAST "xml",
168 NULL
169};
170static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
171#ifndef LIBXML_THREAD_ENABLED
172/*
173 * Optimizer is disabled only when threaded apps are detected while
174 * the library ain't compiled for thread safety.
175 */
176static int xmlXPathDisableOptimizer = 0;
177#endif
178
Owen Taylor3473f882001-02-23 17:55:21 +0000179/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000180 * *
181 * Error handling routines *
182 * *
183 ************************************************************************/
184
William M. Brack08171912003-12-29 02:52:11 +0000185/*
186 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
187 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000188static const char *xmlXPathErrorMessages[] = {
189 "Ok\n",
190 "Number encoding\n",
191 "Unfinished literal\n",
192 "Start of literal\n",
193 "Expected $ for variable reference\n",
194 "Undefined variable\n",
195 "Invalid predicate\n",
196 "Invalid expression\n",
197 "Missing closing curly brace\n",
198 "Unregistered function\n",
199 "Invalid operand\n",
200 "Invalid type\n",
201 "Invalid number of arguments\n",
202 "Invalid context size\n",
203 "Invalid context position\n",
204 "Memory allocation error\n",
205 "Syntax error\n",
206 "Resource error\n",
207 "Sub resource error\n",
208 "Undefined namespace prefix\n",
209 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000210 "Char out of XML range\n",
211 "Invalid or inclomplete context\n"
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000212};
213
214
215/**
216 * xmlXPathErrMemory:
217 * @ctxt: an XPath context
218 * @extra: extra informations
219 *
220 * Handle a redefinition of attribute error
221 */
222static void
223xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
224{
225 if (ctxt != NULL) {
226 if (extra) {
227 xmlChar buf[200];
228
229 xmlStrPrintf(buf, 200,
230 BAD_CAST "Memory allocation failed : %s\n",
231 extra);
232 ctxt->lastError.message = (char *) xmlStrdup(buf);
233 } else {
234 ctxt->lastError.message = (char *)
235 xmlStrdup(BAD_CAST "Memory allocation failed\n");
236 }
237 ctxt->lastError.domain = XML_FROM_XPATH;
238 ctxt->lastError.code = XML_ERR_NO_MEMORY;
239 if (ctxt->error != NULL)
240 ctxt->error(ctxt->userData, &ctxt->lastError);
241 } else {
242 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000243 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000244 NULL, NULL, XML_FROM_XPATH,
245 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
246 extra, NULL, NULL, 0, 0,
247 "Memory allocation failed : %s\n", extra);
248 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000249 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000250 NULL, NULL, XML_FROM_XPATH,
251 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
252 NULL, NULL, NULL, 0, 0,
253 "Memory allocation failed\n");
254 }
255}
256
257/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000258 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000259 * @ctxt: an XPath parser context
260 * @extra: extra informations
261 *
262 * Handle a redefinition of attribute error
263 */
264static void
265xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
266{
267 ctxt->error = XPATH_MEMORY_ERROR;
268 if (ctxt == NULL)
269 xmlXPathErrMemory(NULL, extra);
270 else
271 xmlXPathErrMemory(ctxt->context, extra);
272}
273
274/**
275 * xmlXPathErr:
276 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000277 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000278 *
279 * Handle a Relax NG Parsing error
280 */
281void
282xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
283{
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000284 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000285 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000286 NULL, NULL, XML_FROM_XPATH,
287 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
288 XML_ERR_ERROR, NULL, 0,
289 NULL, NULL, NULL, 0, 0,
290 xmlXPathErrorMessages[error]);
291 return;
292 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000293 ctxt->error = error;
294 if (ctxt->context == NULL) {
295 __xmlRaiseError(NULL, NULL, NULL,
296 NULL, NULL, XML_FROM_XPATH,
297 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
298 XML_ERR_ERROR, NULL, 0,
299 (const char *) ctxt->base, NULL, NULL,
300 ctxt->cur - ctxt->base, 0,
301 xmlXPathErrorMessages[error]);
302 return;
303 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000304 ctxt->context->lastError.domain = XML_FROM_XPATH;
305 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
306 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000307 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000308 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
309 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
310 ctxt->context->lastError.node = ctxt->context->debugNode;
311 if (ctxt->context->error != NULL) {
312 ctxt->context->error(ctxt->context->userData,
313 &ctxt->context->lastError);
314 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000315 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000316 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
317 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
318 XML_ERR_ERROR, NULL, 0,
319 (const char *) ctxt->base, NULL, NULL,
320 ctxt->cur - ctxt->base, 0,
321 xmlXPathErrorMessages[error]);
322 }
323
324}
325
326/**
327 * xmlXPatherror:
328 * @ctxt: the XPath Parser context
329 * @file: the file name
330 * @line: the line number
331 * @no: the error number
332 *
333 * Formats an error message.
334 */
335void
336xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
337 int line ATTRIBUTE_UNUSED, int no) {
338 xmlXPathErr(ctxt, no);
339}
340
341
342/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000343 * *
344 * Parser Types *
345 * *
346 ************************************************************************/
347
348/*
349 * Types are private:
350 */
351
352typedef enum {
353 XPATH_OP_END=0,
354 XPATH_OP_AND,
355 XPATH_OP_OR,
356 XPATH_OP_EQUAL,
357 XPATH_OP_CMP,
358 XPATH_OP_PLUS,
359 XPATH_OP_MULT,
360 XPATH_OP_UNION,
361 XPATH_OP_ROOT,
362 XPATH_OP_NODE,
363 XPATH_OP_RESET,
364 XPATH_OP_COLLECT,
365 XPATH_OP_VALUE,
366 XPATH_OP_VARIABLE,
367 XPATH_OP_FUNCTION,
368 XPATH_OP_ARG,
369 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000370 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000371 XPATH_OP_SORT
372#ifdef LIBXML_XPTR_ENABLED
373 ,XPATH_OP_RANGETO
374#endif
375} xmlXPathOp;
376
377typedef enum {
378 AXIS_ANCESTOR = 1,
379 AXIS_ANCESTOR_OR_SELF,
380 AXIS_ATTRIBUTE,
381 AXIS_CHILD,
382 AXIS_DESCENDANT,
383 AXIS_DESCENDANT_OR_SELF,
384 AXIS_FOLLOWING,
385 AXIS_FOLLOWING_SIBLING,
386 AXIS_NAMESPACE,
387 AXIS_PARENT,
388 AXIS_PRECEDING,
389 AXIS_PRECEDING_SIBLING,
390 AXIS_SELF
391} xmlXPathAxisVal;
392
393typedef enum {
394 NODE_TEST_NONE = 0,
395 NODE_TEST_TYPE = 1,
396 NODE_TEST_PI = 2,
397 NODE_TEST_ALL = 3,
398 NODE_TEST_NS = 4,
399 NODE_TEST_NAME = 5
400} xmlXPathTestVal;
401
402typedef enum {
403 NODE_TYPE_NODE = 0,
404 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
405 NODE_TYPE_TEXT = XML_TEXT_NODE,
406 NODE_TYPE_PI = XML_PI_NODE
407} xmlXPathTypeVal;
408
409
410typedef struct _xmlXPathStepOp xmlXPathStepOp;
411typedef xmlXPathStepOp *xmlXPathStepOpPtr;
412struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000413 xmlXPathOp op; /* The identifier of the operation */
414 int ch1; /* First child */
415 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000416 int value;
417 int value2;
418 int value3;
419 void *value4;
420 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000421 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000422 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000423};
424
425struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000426 int nbStep; /* Number of steps in this expression */
427 int maxStep; /* Maximum number of steps allocated */
428 xmlXPathStepOp *steps; /* ops for computation of this expression */
429 int last; /* index of last step in expression */
430 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000431 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000432#ifdef DEBUG_EVAL_COUNTS
433 int nb;
434 xmlChar *string;
435#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000436};
437
438/************************************************************************
439 * *
440 * Parser Type functions *
441 * *
442 ************************************************************************/
443
444/**
445 * xmlXPathNewCompExpr:
446 *
447 * Create a new Xpath component
448 *
449 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
450 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000451static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000452xmlXPathNewCompExpr(void) {
453 xmlXPathCompExprPtr cur;
454
455 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
456 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000457 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000458 return(NULL);
459 }
460 memset(cur, 0, sizeof(xmlXPathCompExpr));
461 cur->maxStep = 10;
462 cur->nbStep = 0;
463 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
464 sizeof(xmlXPathStepOp));
465 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000466 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000467 xmlFree(cur);
468 return(NULL);
469 }
470 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
471 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000472#ifdef DEBUG_EVAL_COUNTS
473 cur->nb = 0;
474#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000475 return(cur);
476}
477
478/**
479 * xmlXPathFreeCompExpr:
480 * @comp: an XPATH comp
481 *
482 * Free up the memory allocated by @comp
483 */
484void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000485xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
486{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000487 xmlXPathStepOpPtr op;
488 int i;
489
490 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000491 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000492 if (comp->dict == NULL) {
493 for (i = 0; i < comp->nbStep; i++) {
494 op = &comp->steps[i];
495 if (op->value4 != NULL) {
496 if (op->op == XPATH_OP_VALUE)
497 xmlXPathFreeObject(op->value4);
498 else
499 xmlFree(op->value4);
500 }
501 if (op->value5 != NULL)
502 xmlFree(op->value5);
503 }
504 } else {
505 for (i = 0; i < comp->nbStep; i++) {
506 op = &comp->steps[i];
507 if (op->value4 != NULL) {
508 if (op->op == XPATH_OP_VALUE)
509 xmlXPathFreeObject(op->value4);
510 }
511 }
512 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000513 }
514 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000515 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000516 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000517#ifdef DEBUG_EVAL_COUNTS
518 if (comp->string != NULL) {
519 xmlFree(comp->string);
520 }
521#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000522 if (comp->expr != NULL) {
523 xmlFree(comp->expr);
524 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000525
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000526 xmlFree(comp);
527}
528
529/**
530 * xmlXPathCompExprAdd:
531 * @comp: the compiled expression
532 * @ch1: first child index
533 * @ch2: second child index
534 * @op: an op
535 * @value: the first int value
536 * @value2: the second int value
537 * @value3: the third int value
538 * @value4: the first string value
539 * @value5: the second string value
540 *
William M. Brack08171912003-12-29 02:52:11 +0000541 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000542 *
543 * Returns -1 in case of failure, the index otherwise
544 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000545static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000546xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
547 xmlXPathOp op, int value,
548 int value2, int value3, void *value4, void *value5) {
549 if (comp->nbStep >= comp->maxStep) {
550 xmlXPathStepOp *real;
551
552 comp->maxStep *= 2;
553 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
554 comp->maxStep * sizeof(xmlXPathStepOp));
555 if (real == NULL) {
556 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000557 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000558 return(-1);
559 }
560 comp->steps = real;
561 }
562 comp->last = comp->nbStep;
563 comp->steps[comp->nbStep].ch1 = ch1;
564 comp->steps[comp->nbStep].ch2 = ch2;
565 comp->steps[comp->nbStep].op = op;
566 comp->steps[comp->nbStep].value = value;
567 comp->steps[comp->nbStep].value2 = value2;
568 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000569 if ((comp->dict != NULL) &&
570 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
571 (op == XPATH_OP_COLLECT))) {
572 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000573 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000574 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000575 xmlFree(value4);
576 } else
577 comp->steps[comp->nbStep].value4 = NULL;
578 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000579 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000580 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000581 xmlFree(value5);
582 } else
583 comp->steps[comp->nbStep].value5 = NULL;
584 } else {
585 comp->steps[comp->nbStep].value4 = value4;
586 comp->steps[comp->nbStep].value5 = value5;
587 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000588 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000589 return(comp->nbStep++);
590}
591
Daniel Veillardf06307e2001-07-03 10:35:50 +0000592/**
593 * xmlXPathCompSwap:
594 * @comp: the compiled expression
595 * @op: operation index
596 *
597 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000598 */
599static void
600xmlXPathCompSwap(xmlXPathStepOpPtr op) {
601 int tmp;
602
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000603#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000604 /*
605 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000606 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000607 * application
608 */
609 if (xmlXPathDisableOptimizer)
610 return;
611#endif
612
Daniel Veillardf06307e2001-07-03 10:35:50 +0000613 tmp = op->ch1;
614 op->ch1 = op->ch2;
615 op->ch2 = tmp;
616}
617
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000618#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
619 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
620 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000621#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
622 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
623 (op), (val), (val2), (val3), (val4), (val5))
624
625#define PUSH_LEAVE_EXPR(op, val, val2) \
626xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
627
628#define PUSH_UNARY_EXPR(op, ch, val, val2) \
629xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
630
631#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000632xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
633 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000634
635/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000636 * *
637 * Debugging related functions *
638 * *
639 ************************************************************************/
640
Owen Taylor3473f882001-02-23 17:55:21 +0000641#define STRANGE \
642 xmlGenericError(xmlGenericErrorContext, \
643 "Internal error at %s:%d\n", \
644 __FILE__, __LINE__);
645
646#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000647static void
648xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000649 int i;
650 char shift[100];
651
652 for (i = 0;((i < depth) && (i < 25));i++)
653 shift[2 * i] = shift[2 * i + 1] = ' ';
654 shift[2 * i] = shift[2 * i + 1] = 0;
655 if (cur == NULL) {
656 fprintf(output, shift);
657 fprintf(output, "Node is NULL !\n");
658 return;
659
660 }
661
662 if ((cur->type == XML_DOCUMENT_NODE) ||
663 (cur->type == XML_HTML_DOCUMENT_NODE)) {
664 fprintf(output, shift);
665 fprintf(output, " /\n");
666 } else if (cur->type == XML_ATTRIBUTE_NODE)
667 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
668 else
669 xmlDebugDumpOneNode(output, cur, depth);
670}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000671static void
672xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000673 xmlNodePtr tmp;
674 int i;
675 char shift[100];
676
677 for (i = 0;((i < depth) && (i < 25));i++)
678 shift[2 * i] = shift[2 * i + 1] = ' ';
679 shift[2 * i] = shift[2 * i + 1] = 0;
680 if (cur == NULL) {
681 fprintf(output, shift);
682 fprintf(output, "Node is NULL !\n");
683 return;
684
685 }
686
687 while (cur != NULL) {
688 tmp = cur;
689 cur = cur->next;
690 xmlDebugDumpOneNode(output, tmp, depth);
691 }
692}
Owen Taylor3473f882001-02-23 17:55:21 +0000693
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000694static void
695xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000696 int i;
697 char shift[100];
698
699 for (i = 0;((i < depth) && (i < 25));i++)
700 shift[2 * i] = shift[2 * i + 1] = ' ';
701 shift[2 * i] = shift[2 * i + 1] = 0;
702
703 if (cur == NULL) {
704 fprintf(output, shift);
705 fprintf(output, "NodeSet is NULL !\n");
706 return;
707
708 }
709
Daniel Veillard911f49a2001-04-07 15:39:35 +0000710 if (cur != NULL) {
711 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
712 for (i = 0;i < cur->nodeNr;i++) {
713 fprintf(output, shift);
714 fprintf(output, "%d", i + 1);
715 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
716 }
Owen Taylor3473f882001-02-23 17:55:21 +0000717 }
718}
719
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000720static void
721xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000722 int i;
723 char shift[100];
724
725 for (i = 0;((i < depth) && (i < 25));i++)
726 shift[2 * i] = shift[2 * i + 1] = ' ';
727 shift[2 * i] = shift[2 * i + 1] = 0;
728
729 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
730 fprintf(output, shift);
731 fprintf(output, "Value Tree is NULL !\n");
732 return;
733
734 }
735
736 fprintf(output, shift);
737 fprintf(output, "%d", i + 1);
738 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
739}
Owen Taylor3473f882001-02-23 17:55:21 +0000740#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000741static void
742xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000743 int i;
744 char shift[100];
745
746 for (i = 0;((i < depth) && (i < 25));i++)
747 shift[2 * i] = shift[2 * i + 1] = ' ';
748 shift[2 * i] = shift[2 * i + 1] = 0;
749
750 if (cur == NULL) {
751 fprintf(output, shift);
752 fprintf(output, "LocationSet is NULL !\n");
753 return;
754
755 }
756
757 for (i = 0;i < cur->locNr;i++) {
758 fprintf(output, shift);
759 fprintf(output, "%d : ", i + 1);
760 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
761 }
762}
Daniel Veillard017b1082001-06-21 11:20:21 +0000763#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000764
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000765/**
766 * xmlXPathDebugDumpObject:
767 * @output: the FILE * to dump the output
768 * @cur: the object to inspect
769 * @depth: indentation level
770 *
771 * Dump the content of the object for debugging purposes
772 */
773void
774xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000775 int i;
776 char shift[100];
777
Daniel Veillarda82b1822004-11-08 16:24:57 +0000778 if (output == NULL) return;
779
Owen Taylor3473f882001-02-23 17:55:21 +0000780 for (i = 0;((i < depth) && (i < 25));i++)
781 shift[2 * i] = shift[2 * i + 1] = ' ';
782 shift[2 * i] = shift[2 * i + 1] = 0;
783
784 fprintf(output, shift);
785
786 if (cur == NULL) {
787 fprintf(output, "Object is empty (NULL)\n");
788 return;
789 }
790 switch(cur->type) {
791 case XPATH_UNDEFINED:
792 fprintf(output, "Object is uninitialized\n");
793 break;
794 case XPATH_NODESET:
795 fprintf(output, "Object is a Node Set :\n");
796 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
797 break;
798 case XPATH_XSLT_TREE:
799 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000800 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000801 break;
802 case XPATH_BOOLEAN:
803 fprintf(output, "Object is a Boolean : ");
804 if (cur->boolval) fprintf(output, "true\n");
805 else fprintf(output, "false\n");
806 break;
807 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000808 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000809 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000810 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000811 break;
812 case -1:
813 fprintf(output, "Object is a number : -Infinity\n");
814 break;
815 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000816 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000817 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000818 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
819 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000820 } else {
821 fprintf(output, "Object is a number : %0g\n", cur->floatval);
822 }
823 }
Owen Taylor3473f882001-02-23 17:55:21 +0000824 break;
825 case XPATH_STRING:
826 fprintf(output, "Object is a string : ");
827 xmlDebugDumpString(output, cur->stringval);
828 fprintf(output, "\n");
829 break;
830 case XPATH_POINT:
831 fprintf(output, "Object is a point : index %d in node", cur->index);
832 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
833 fprintf(output, "\n");
834 break;
835 case XPATH_RANGE:
836 if ((cur->user2 == NULL) ||
837 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
838 fprintf(output, "Object is a collapsed range :\n");
839 fprintf(output, shift);
840 if (cur->index >= 0)
841 fprintf(output, "index %d in ", cur->index);
842 fprintf(output, "node\n");
843 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
844 depth + 1);
845 } else {
846 fprintf(output, "Object is a range :\n");
847 fprintf(output, shift);
848 fprintf(output, "From ");
849 if (cur->index >= 0)
850 fprintf(output, "index %d in ", cur->index);
851 fprintf(output, "node\n");
852 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
853 depth + 1);
854 fprintf(output, shift);
855 fprintf(output, "To ");
856 if (cur->index2 >= 0)
857 fprintf(output, "index %d in ", cur->index2);
858 fprintf(output, "node\n");
859 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
860 depth + 1);
861 fprintf(output, "\n");
862 }
863 break;
864 case XPATH_LOCATIONSET:
865#if defined(LIBXML_XPTR_ENABLED)
866 fprintf(output, "Object is a Location Set:\n");
867 xmlXPathDebugDumpLocationSet(output,
868 (xmlLocationSetPtr) cur->user, depth);
869#endif
870 break;
871 case XPATH_USERS:
872 fprintf(output, "Object is user defined\n");
873 break;
874 }
875}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000876
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000877static void
878xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000879 xmlXPathStepOpPtr op, int depth) {
880 int i;
881 char shift[100];
882
883 for (i = 0;((i < depth) && (i < 25));i++)
884 shift[2 * i] = shift[2 * i + 1] = ' ';
885 shift[2 * i] = shift[2 * i + 1] = 0;
886
887 fprintf(output, shift);
888 if (op == NULL) {
889 fprintf(output, "Step is NULL\n");
890 return;
891 }
892 switch (op->op) {
893 case XPATH_OP_END:
894 fprintf(output, "END"); break;
895 case XPATH_OP_AND:
896 fprintf(output, "AND"); break;
897 case XPATH_OP_OR:
898 fprintf(output, "OR"); break;
899 case XPATH_OP_EQUAL:
900 if (op->value)
901 fprintf(output, "EQUAL =");
902 else
903 fprintf(output, "EQUAL !=");
904 break;
905 case XPATH_OP_CMP:
906 if (op->value)
907 fprintf(output, "CMP <");
908 else
909 fprintf(output, "CMP >");
910 if (!op->value2)
911 fprintf(output, "=");
912 break;
913 case XPATH_OP_PLUS:
914 if (op->value == 0)
915 fprintf(output, "PLUS -");
916 else if (op->value == 1)
917 fprintf(output, "PLUS +");
918 else if (op->value == 2)
919 fprintf(output, "PLUS unary -");
920 else if (op->value == 3)
921 fprintf(output, "PLUS unary - -");
922 break;
923 case XPATH_OP_MULT:
924 if (op->value == 0)
925 fprintf(output, "MULT *");
926 else if (op->value == 1)
927 fprintf(output, "MULT div");
928 else
929 fprintf(output, "MULT mod");
930 break;
931 case XPATH_OP_UNION:
932 fprintf(output, "UNION"); break;
933 case XPATH_OP_ROOT:
934 fprintf(output, "ROOT"); break;
935 case XPATH_OP_NODE:
936 fprintf(output, "NODE"); break;
937 case XPATH_OP_RESET:
938 fprintf(output, "RESET"); break;
939 case XPATH_OP_SORT:
940 fprintf(output, "SORT"); break;
941 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000942 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
943 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
944 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000945 const xmlChar *prefix = op->value4;
946 const xmlChar *name = op->value5;
947
948 fprintf(output, "COLLECT ");
949 switch (axis) {
950 case AXIS_ANCESTOR:
951 fprintf(output, " 'ancestors' "); break;
952 case AXIS_ANCESTOR_OR_SELF:
953 fprintf(output, " 'ancestors-or-self' "); break;
954 case AXIS_ATTRIBUTE:
955 fprintf(output, " 'attributes' "); break;
956 case AXIS_CHILD:
957 fprintf(output, " 'child' "); break;
958 case AXIS_DESCENDANT:
959 fprintf(output, " 'descendant' "); break;
960 case AXIS_DESCENDANT_OR_SELF:
961 fprintf(output, " 'descendant-or-self' "); break;
962 case AXIS_FOLLOWING:
963 fprintf(output, " 'following' "); break;
964 case AXIS_FOLLOWING_SIBLING:
965 fprintf(output, " 'following-siblings' "); break;
966 case AXIS_NAMESPACE:
967 fprintf(output, " 'namespace' "); break;
968 case AXIS_PARENT:
969 fprintf(output, " 'parent' "); break;
970 case AXIS_PRECEDING:
971 fprintf(output, " 'preceding' "); break;
972 case AXIS_PRECEDING_SIBLING:
973 fprintf(output, " 'preceding-sibling' "); break;
974 case AXIS_SELF:
975 fprintf(output, " 'self' "); break;
976 }
977 switch (test) {
978 case NODE_TEST_NONE:
979 fprintf(output, "'none' "); break;
980 case NODE_TEST_TYPE:
981 fprintf(output, "'type' "); break;
982 case NODE_TEST_PI:
983 fprintf(output, "'PI' "); break;
984 case NODE_TEST_ALL:
985 fprintf(output, "'all' "); break;
986 case NODE_TEST_NS:
987 fprintf(output, "'namespace' "); break;
988 case NODE_TEST_NAME:
989 fprintf(output, "'name' "); break;
990 }
991 switch (type) {
992 case NODE_TYPE_NODE:
993 fprintf(output, "'node' "); break;
994 case NODE_TYPE_COMMENT:
995 fprintf(output, "'comment' "); break;
996 case NODE_TYPE_TEXT:
997 fprintf(output, "'text' "); break;
998 case NODE_TYPE_PI:
999 fprintf(output, "'PI' "); break;
1000 }
1001 if (prefix != NULL)
1002 fprintf(output, "%s:", prefix);
1003 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001004 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001005 break;
1006
1007 }
1008 case XPATH_OP_VALUE: {
1009 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1010
1011 fprintf(output, "ELEM ");
1012 xmlXPathDebugDumpObject(output, object, 0);
1013 goto finish;
1014 }
1015 case XPATH_OP_VARIABLE: {
1016 const xmlChar *prefix = op->value5;
1017 const xmlChar *name = op->value4;
1018
1019 if (prefix != NULL)
1020 fprintf(output, "VARIABLE %s:%s", prefix, name);
1021 else
1022 fprintf(output, "VARIABLE %s", name);
1023 break;
1024 }
1025 case XPATH_OP_FUNCTION: {
1026 int nbargs = op->value;
1027 const xmlChar *prefix = op->value5;
1028 const xmlChar *name = op->value4;
1029
1030 if (prefix != NULL)
1031 fprintf(output, "FUNCTION %s:%s(%d args)",
1032 prefix, name, nbargs);
1033 else
1034 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1035 break;
1036 }
1037 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1038 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001039 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001040#ifdef LIBXML_XPTR_ENABLED
1041 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1042#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001043 default:
1044 fprintf(output, "UNKNOWN %d\n", op->op); return;
1045 }
1046 fprintf(output, "\n");
1047finish:
1048 if (op->ch1 >= 0)
1049 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1050 if (op->ch2 >= 0)
1051 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1052}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001053
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001054/**
1055 * xmlXPathDebugDumpCompExpr:
1056 * @output: the FILE * for the output
1057 * @comp: the precompiled XPath expression
1058 * @depth: the indentation level.
1059 *
1060 * Dumps the tree of the compiled XPath expression.
1061 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001062void
1063xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1064 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001065 int i;
1066 char shift[100];
1067
Daniel Veillarda82b1822004-11-08 16:24:57 +00001068 if ((output == NULL) || (comp == NULL)) return;
1069
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001070 for (i = 0;((i < depth) && (i < 25));i++)
1071 shift[2 * i] = shift[2 * i + 1] = ' ';
1072 shift[2 * i] = shift[2 * i + 1] = 0;
1073
1074 fprintf(output, shift);
1075
1076 if (comp == NULL) {
1077 fprintf(output, "Compiled Expression is NULL\n");
1078 return;
1079 }
1080 fprintf(output, "Compiled Expression : %d elements\n",
1081 comp->nbStep);
1082 i = comp->last;
1083 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1084}
Daniel Veillard017b1082001-06-21 11:20:21 +00001085#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001086
1087/************************************************************************
1088 * *
1089 * Parser stacks related functions and macros *
1090 * *
1091 ************************************************************************/
1092
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001093/**
1094 * valuePop:
1095 * @ctxt: an XPath evaluation context
1096 *
1097 * Pops the top XPath object from the value stack
1098 *
1099 * Returns the XPath object just removed
1100 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001101extern xmlXPathObjectPtr
1102valuePop(xmlXPathParserContextPtr ctxt)
1103{
1104 xmlXPathObjectPtr ret;
1105
Daniel Veillarda82b1822004-11-08 16:24:57 +00001106 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard1c732d22002-11-30 11:22:59 +00001107 return (0);
1108 ctxt->valueNr--;
1109 if (ctxt->valueNr > 0)
1110 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1111 else
1112 ctxt->value = NULL;
1113 ret = ctxt->valueTab[ctxt->valueNr];
1114 ctxt->valueTab[ctxt->valueNr] = 0;
1115 return (ret);
1116}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001117/**
1118 * valuePush:
1119 * @ctxt: an XPath evaluation context
1120 * @value: the XPath object
1121 *
1122 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001123 *
1124 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001125 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001126extern int
1127valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1128{
Daniel Veillarda82b1822004-11-08 16:24:57 +00001129 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00001130 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001131 xmlXPathObjectPtr *tmp;
1132
1133 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1134 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00001135 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001136 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00001137 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1138 return (0);
1139 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001140 ctxt->valueMax *= 2;
1141 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00001142 }
1143 ctxt->valueTab[ctxt->valueNr] = value;
1144 ctxt->value = value;
1145 return (ctxt->valueNr++);
1146}
Owen Taylor3473f882001-02-23 17:55:21 +00001147
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001148/**
1149 * xmlXPathPopBoolean:
1150 * @ctxt: an XPath parser context
1151 *
1152 * Pops a boolean from the stack, handling conversion if needed.
1153 * Check error with #xmlXPathCheckError.
1154 *
1155 * Returns the boolean
1156 */
1157int
1158xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1159 xmlXPathObjectPtr obj;
1160 int ret;
1161
1162 obj = valuePop(ctxt);
1163 if (obj == NULL) {
1164 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1165 return(0);
1166 }
William M. Brack08171912003-12-29 02:52:11 +00001167 if (obj->type != XPATH_BOOLEAN)
1168 ret = xmlXPathCastToBoolean(obj);
1169 else
1170 ret = obj->boolval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001171 xmlXPathFreeObject(obj);
1172 return(ret);
1173}
1174
1175/**
1176 * xmlXPathPopNumber:
1177 * @ctxt: an XPath parser context
1178 *
1179 * Pops a number from the stack, handling conversion if needed.
1180 * Check error with #xmlXPathCheckError.
1181 *
1182 * Returns the number
1183 */
1184double
1185xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1186 xmlXPathObjectPtr obj;
1187 double ret;
1188
1189 obj = valuePop(ctxt);
1190 if (obj == NULL) {
1191 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1192 return(0);
1193 }
William M. Brack08171912003-12-29 02:52:11 +00001194 if (obj->type != XPATH_NUMBER)
1195 ret = xmlXPathCastToNumber(obj);
1196 else
1197 ret = obj->floatval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001198 xmlXPathFreeObject(obj);
1199 return(ret);
1200}
1201
1202/**
1203 * xmlXPathPopString:
1204 * @ctxt: an XPath parser context
1205 *
1206 * Pops a string from the stack, handling conversion if needed.
1207 * Check error with #xmlXPathCheckError.
1208 *
1209 * Returns the string
1210 */
1211xmlChar *
1212xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1213 xmlXPathObjectPtr obj;
1214 xmlChar * ret;
1215
1216 obj = valuePop(ctxt);
1217 if (obj == NULL) {
1218 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1219 return(NULL);
1220 }
William M. Brack08171912003-12-29 02:52:11 +00001221 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001222 /* TODO: needs refactoring somewhere else */
1223 if (obj->stringval == ret)
1224 obj->stringval = NULL;
1225 xmlXPathFreeObject(obj);
1226 return(ret);
1227}
1228
1229/**
1230 * xmlXPathPopNodeSet:
1231 * @ctxt: an XPath parser context
1232 *
1233 * Pops a node-set from the stack, handling conversion if needed.
1234 * Check error with #xmlXPathCheckError.
1235 *
1236 * Returns the node-set
1237 */
1238xmlNodeSetPtr
1239xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1240 xmlXPathObjectPtr obj;
1241 xmlNodeSetPtr ret;
1242
Daniel Veillardf2a36f92004-11-08 17:55:01 +00001243 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001244 if (ctxt->value == NULL) {
1245 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1246 return(NULL);
1247 }
1248 if (!xmlXPathStackIsNodeSet(ctxt)) {
1249 xmlXPathSetTypeError(ctxt);
1250 return(NULL);
1251 }
1252 obj = valuePop(ctxt);
1253 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00001254#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00001255 /* to fix memory leak of not clearing obj->user */
1256 if (obj->boolval && obj->user != NULL)
1257 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00001258#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001259 xmlXPathFreeNodeSetList(obj);
1260 return(ret);
1261}
1262
1263/**
1264 * xmlXPathPopExternal:
1265 * @ctxt: an XPath parser context
1266 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001267 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001268 * Check error with #xmlXPathCheckError.
1269 *
1270 * Returns the object
1271 */
1272void *
1273xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1274 xmlXPathObjectPtr obj;
1275 void * ret;
1276
Daniel Veillarda82b1822004-11-08 16:24:57 +00001277 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001278 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1279 return(NULL);
1280 }
1281 if (ctxt->value->type != XPATH_USERS) {
1282 xmlXPathSetTypeError(ctxt);
1283 return(NULL);
1284 }
1285 obj = valuePop(ctxt);
1286 ret = obj->user;
1287 xmlXPathFreeObject(obj);
1288 return(ret);
1289}
1290
Owen Taylor3473f882001-02-23 17:55:21 +00001291/*
1292 * Macros for accessing the content. Those should be used only by the parser,
1293 * and not exported.
1294 *
1295 * Dirty macros, i.e. one need to make assumption on the context to use them
1296 *
1297 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1298 * CUR returns the current xmlChar value, i.e. a 8 bit value
1299 * in ISO-Latin or UTF-8.
1300 * This should be used internally by the parser
1301 * only to compare to ASCII values otherwise it would break when
1302 * running with UTF-8 encoding.
1303 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1304 * to compare on ASCII based substring.
1305 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1306 * strings within the parser.
1307 * CURRENT Returns the current char value, with the full decoding of
1308 * UTF-8 if we are using this mode. It returns an int.
1309 * NEXT Skip to the next character, this does the proper decoding
1310 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1311 * It returns the pointer to the current xmlChar.
1312 */
1313
1314#define CUR (*ctxt->cur)
1315#define SKIP(val) ctxt->cur += (val)
1316#define NXT(val) ctxt->cur[(val)]
1317#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001318#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1319
1320#define COPY_BUF(l,b,i,v) \
1321 if (l == 1) b[i++] = (xmlChar) v; \
1322 else i += xmlCopyChar(l,&b[i],v)
1323
1324#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001325
1326#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001327 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001328
1329#define CURRENT (*ctxt->cur)
1330#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1331
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001332
1333#ifndef DBL_DIG
1334#define DBL_DIG 16
1335#endif
1336#ifndef DBL_EPSILON
1337#define DBL_EPSILON 1E-9
1338#endif
1339
1340#define UPPER_DOUBLE 1E9
1341#define LOWER_DOUBLE 1E-5
1342
1343#define INTEGER_DIGITS DBL_DIG
1344#define FRACTION_DIGITS (DBL_DIG + 1)
1345#define EXPONENT_DIGITS (3 + 2)
1346
1347/**
1348 * xmlXPathFormatNumber:
1349 * @number: number to format
1350 * @buffer: output buffer
1351 * @buffersize: size of output buffer
1352 *
1353 * Convert the number into a string representation.
1354 */
1355static void
1356xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1357{
Daniel Veillardcda96922001-08-21 10:56:31 +00001358 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001359 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001360 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001361 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001362 break;
1363 case -1:
1364 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001365 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001366 break;
1367 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001368 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001369 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001370 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001371 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001372 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001373 } else if (number == ((int) number)) {
1374 char work[30];
1375 char *ptr, *cur;
1376 int res, value = (int) number;
1377
1378 ptr = &buffer[0];
1379 if (value < 0) {
1380 *ptr++ = '-';
1381 value = -value;
1382 }
1383 if (value == 0) {
1384 *ptr++ = '0';
1385 } else {
1386 cur = &work[0];
1387 while (value != 0) {
1388 res = value % 10;
1389 value = value / 10;
1390 *cur++ = '0' + res;
1391 }
1392 cur--;
1393 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1394 *ptr++ = *cur--;
1395 }
1396 }
1397 if (ptr - buffer < buffersize) {
1398 *ptr = 0;
1399 } else if (buffersize > 0) {
1400 ptr--;
1401 *ptr = 0;
1402 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001403 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001404 /* 3 is sign, decimal point, and terminating zero */
1405 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1406 int integer_place, fraction_place;
1407 char *ptr;
1408 char *after_fraction;
1409 double absolute_value;
1410 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001411
Bjorn Reese70a9da52001-04-21 16:57:29 +00001412 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001413
Bjorn Reese70a9da52001-04-21 16:57:29 +00001414 /*
1415 * First choose format - scientific or regular floating point.
1416 * In either case, result is in work, and after_fraction points
1417 * just past the fractional part.
1418 */
1419 if ( ((absolute_value > UPPER_DOUBLE) ||
1420 (absolute_value < LOWER_DOUBLE)) &&
1421 (absolute_value != 0.0) ) {
1422 /* Use scientific notation */
1423 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1424 fraction_place = DBL_DIG - 1;
1425 snprintf(work, sizeof(work),"%*.*e",
1426 integer_place, fraction_place, number);
1427 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001428 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001429 else {
1430 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001431 if (absolute_value > 0.0)
1432 integer_place = 1 + (int)log10(absolute_value);
1433 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001434 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001435 fraction_place = (integer_place > 0)
1436 ? DBL_DIG - integer_place
1437 : DBL_DIG;
1438 size = snprintf(work, sizeof(work), "%0.*f",
1439 fraction_place, number);
1440 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001441 }
1442
Bjorn Reese70a9da52001-04-21 16:57:29 +00001443 /* Remove fractional trailing zeroes */
1444 ptr = after_fraction;
1445 while (*(--ptr) == '0')
1446 ;
1447 if (*ptr != '.')
1448 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001449 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001450
1451 /* Finally copy result back to caller */
1452 size = strlen(work) + 1;
1453 if (size > buffersize) {
1454 work[buffersize - 1] = 0;
1455 size = buffersize;
1456 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001457 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001458 }
1459 break;
1460 }
1461}
1462
Owen Taylor3473f882001-02-23 17:55:21 +00001463
1464/************************************************************************
1465 * *
1466 * Routines to handle NodeSets *
1467 * *
1468 ************************************************************************/
1469
1470/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001471 * xmlXPathOrderDocElems:
1472 * @doc: an input document
1473 *
1474 * Call this routine to speed up XPath computation on static documents.
1475 * This stamps all the element nodes with the document order
1476 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00001477 * field, the value stored is actually - the node number (starting at -1)
1478 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001479 *
William M. Brack08171912003-12-29 02:52:11 +00001480 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001481 * of error.
1482 */
1483long
1484xmlXPathOrderDocElems(xmlDocPtr doc) {
1485 long count = 0;
1486 xmlNodePtr cur;
1487
1488 if (doc == NULL)
1489 return(-1);
1490 cur = doc->children;
1491 while (cur != NULL) {
1492 if (cur->type == XML_ELEMENT_NODE) {
1493 cur->content = (void *) (-(++count));
1494 if (cur->children != NULL) {
1495 cur = cur->children;
1496 continue;
1497 }
1498 }
1499 if (cur->next != NULL) {
1500 cur = cur->next;
1501 continue;
1502 }
1503 do {
1504 cur = cur->parent;
1505 if (cur == NULL)
1506 break;
1507 if (cur == (xmlNodePtr) doc) {
1508 cur = NULL;
1509 break;
1510 }
1511 if (cur->next != NULL) {
1512 cur = cur->next;
1513 break;
1514 }
1515 } while (cur != NULL);
1516 }
1517 return(count);
1518}
1519
1520/**
Owen Taylor3473f882001-02-23 17:55:21 +00001521 * xmlXPathCmpNodes:
1522 * @node1: the first node
1523 * @node2: the second node
1524 *
1525 * Compare two nodes w.r.t document order
1526 *
1527 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00001528 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001529 */
1530int
1531xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1532 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001533 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001534 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001535 xmlNodePtr cur, root;
1536
1537 if ((node1 == NULL) || (node2 == NULL))
1538 return(-2);
1539 /*
1540 * a couple of optimizations which will avoid computations in most cases
1541 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001542 if (node1->type == XML_ATTRIBUTE_NODE) {
1543 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001544 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001545 node1 = node1->parent;
1546 }
1547 if (node2->type == XML_ATTRIBUTE_NODE) {
1548 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001549 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001550 node2 = node2->parent;
1551 }
1552 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001553 if (attr1 == attr2) {
1554 /* not required, but we keep attributes in order */
1555 if (attr1 != 0) {
1556 cur = attrNode2->prev;
1557 while (cur != NULL) {
1558 if (cur == attrNode1)
1559 return (1);
1560 cur = cur->prev;
1561 }
1562 return (-1);
1563 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001564 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001565 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001566 if (attr2 == 1)
1567 return(1);
1568 return(-1);
1569 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001570 if ((node1->type == XML_NAMESPACE_DECL) ||
1571 (node2->type == XML_NAMESPACE_DECL))
1572 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001573 if (node1 == node2->prev)
1574 return(1);
1575 if (node1 == node2->next)
1576 return(-1);
1577
1578 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001579 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001580 */
1581 if ((node1->type == XML_ELEMENT_NODE) &&
1582 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001583 (0 > (long) node1->content) &&
1584 (0 > (long) node2->content) &&
1585 (node1->doc == node2->doc)) {
1586 long l1, l2;
1587
1588 l1 = -((long) node1->content);
1589 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001590 if (l1 < l2)
1591 return(1);
1592 if (l1 > l2)
1593 return(-1);
1594 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001595
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001596 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001597 * compute depth to root
1598 */
1599 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1600 if (cur == node1)
1601 return(1);
1602 depth2++;
1603 }
1604 root = cur;
1605 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1606 if (cur == node2)
1607 return(-1);
1608 depth1++;
1609 }
1610 /*
1611 * Distinct document (or distinct entities :-( ) case.
1612 */
1613 if (root != cur) {
1614 return(-2);
1615 }
1616 /*
1617 * get the nearest common ancestor.
1618 */
1619 while (depth1 > depth2) {
1620 depth1--;
1621 node1 = node1->parent;
1622 }
1623 while (depth2 > depth1) {
1624 depth2--;
1625 node2 = node2->parent;
1626 }
1627 while (node1->parent != node2->parent) {
1628 node1 = node1->parent;
1629 node2 = node2->parent;
1630 /* should not happen but just in case ... */
1631 if ((node1 == NULL) || (node2 == NULL))
1632 return(-2);
1633 }
1634 /*
1635 * Find who's first.
1636 */
Daniel Veillardf49be472004-02-17 11:48:18 +00001637 if (node1 == node2->prev)
1638 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001639 if (node1 == node2->next)
1640 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00001641 /*
1642 * Speedup using document order if availble.
1643 */
1644 if ((node1->type == XML_ELEMENT_NODE) &&
1645 (node2->type == XML_ELEMENT_NODE) &&
1646 (0 > (long) node1->content) &&
1647 (0 > (long) node2->content) &&
1648 (node1->doc == node2->doc)) {
1649 long l1, l2;
1650
1651 l1 = -((long) node1->content);
1652 l2 = -((long) node2->content);
1653 if (l1 < l2)
1654 return(1);
1655 if (l1 > l2)
1656 return(-1);
1657 }
1658
Owen Taylor3473f882001-02-23 17:55:21 +00001659 for (cur = node1->next;cur != NULL;cur = cur->next)
1660 if (cur == node2)
1661 return(1);
1662 return(-1); /* assume there is no sibling list corruption */
1663}
1664
1665/**
1666 * xmlXPathNodeSetSort:
1667 * @set: the node set
1668 *
1669 * Sort the node set in document order
1670 */
1671void
1672xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001673 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001674 xmlNodePtr tmp;
1675
1676 if (set == NULL)
1677 return;
1678
1679 /* Use Shell's sort to sort the node-set */
1680 len = set->nodeNr;
1681 for (incr = len / 2; incr > 0; incr /= 2) {
1682 for (i = incr; i < len; i++) {
1683 j = i - incr;
1684 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001685 if (xmlXPathCmpNodes(set->nodeTab[j],
1686 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001687 tmp = set->nodeTab[j];
1688 set->nodeTab[j] = set->nodeTab[j + incr];
1689 set->nodeTab[j + incr] = tmp;
1690 j -= incr;
1691 } else
1692 break;
1693 }
1694 }
1695 }
1696}
1697
1698#define XML_NODESET_DEFAULT 10
1699/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001700 * xmlXPathNodeSetDupNs:
1701 * @node: the parent node of the namespace XPath node
1702 * @ns: the libxml namespace declaration node.
1703 *
1704 * Namespace node in libxml don't match the XPath semantic. In a node set
1705 * the namespace nodes are duplicated and the next pointer is set to the
1706 * parent node in the XPath semantic.
1707 *
1708 * Returns the newly created object.
1709 */
1710static xmlNodePtr
1711xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1712 xmlNsPtr cur;
1713
1714 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1715 return(NULL);
1716 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1717 return((xmlNodePtr) ns);
1718
1719 /*
1720 * Allocate a new Namespace and fill the fields.
1721 */
1722 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1723 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001724 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001725 return(NULL);
1726 }
1727 memset(cur, 0, sizeof(xmlNs));
1728 cur->type = XML_NAMESPACE_DECL;
1729 if (ns->href != NULL)
1730 cur->href = xmlStrdup(ns->href);
1731 if (ns->prefix != NULL)
1732 cur->prefix = xmlStrdup(ns->prefix);
1733 cur->next = (xmlNsPtr) node;
1734 return((xmlNodePtr) cur);
1735}
1736
1737/**
1738 * xmlXPathNodeSetFreeNs:
1739 * @ns: the XPath namespace node found in a nodeset.
1740 *
William M. Brack08171912003-12-29 02:52:11 +00001741 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001742 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00001743 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001744 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001745void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001746xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1747 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1748 return;
1749
1750 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1751 if (ns->href != NULL)
1752 xmlFree((xmlChar *)ns->href);
1753 if (ns->prefix != NULL)
1754 xmlFree((xmlChar *)ns->prefix);
1755 xmlFree(ns);
1756 }
1757}
1758
1759/**
Owen Taylor3473f882001-02-23 17:55:21 +00001760 * xmlXPathNodeSetCreate:
1761 * @val: an initial xmlNodePtr, or NULL
1762 *
1763 * Create a new xmlNodeSetPtr of type double and of value @val
1764 *
1765 * Returns the newly created object.
1766 */
1767xmlNodeSetPtr
1768xmlXPathNodeSetCreate(xmlNodePtr val) {
1769 xmlNodeSetPtr ret;
1770
1771 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1772 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001773 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001774 return(NULL);
1775 }
1776 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1777 if (val != NULL) {
1778 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1779 sizeof(xmlNodePtr));
1780 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001781 xmlXPathErrMemory(NULL, "creating nodeset\n");
1782 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001783 return(NULL);
1784 }
1785 memset(ret->nodeTab, 0 ,
1786 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1787 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001788 if (val->type == XML_NAMESPACE_DECL) {
1789 xmlNsPtr ns = (xmlNsPtr) val;
1790
1791 ret->nodeTab[ret->nodeNr++] =
1792 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1793 } else
1794 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001795 }
1796 return(ret);
1797}
1798
1799/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001800 * xmlXPathNodeSetContains:
1801 * @cur: the node-set
1802 * @val: the node
1803 *
1804 * checks whether @cur contains @val
1805 *
1806 * Returns true (1) if @cur contains @val, false (0) otherwise
1807 */
1808int
1809xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1810 int i;
1811
Daniel Veillarda82b1822004-11-08 16:24:57 +00001812 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001813 if (val->type == XML_NAMESPACE_DECL) {
1814 for (i = 0; i < cur->nodeNr; i++) {
1815 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1816 xmlNsPtr ns1, ns2;
1817
1818 ns1 = (xmlNsPtr) val;
1819 ns2 = (xmlNsPtr) cur->nodeTab[i];
1820 if (ns1 == ns2)
1821 return(1);
1822 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1823 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1824 return(1);
1825 }
1826 }
1827 } else {
1828 for (i = 0; i < cur->nodeNr; i++) {
1829 if (cur->nodeTab[i] == val)
1830 return(1);
1831 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001832 }
1833 return(0);
1834}
1835
1836/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001837 * xmlXPathNodeSetAddNs:
1838 * @cur: the initial node set
1839 * @node: the hosting node
1840 * @ns: a the namespace node
1841 *
1842 * add a new namespace node to an existing NodeSet
1843 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001844void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001845xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1846 int i;
1847
Daniel Veillarda82b1822004-11-08 16:24:57 +00001848
1849 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
1850 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001851 (node->type != XML_ELEMENT_NODE))
1852 return;
1853
William M. Brack08171912003-12-29 02:52:11 +00001854 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001855 /*
William M. Brack08171912003-12-29 02:52:11 +00001856 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001857 */
1858 for (i = 0;i < cur->nodeNr;i++) {
1859 if ((cur->nodeTab[i] != NULL) &&
1860 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001861 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001862 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1863 return;
1864 }
1865
1866 /*
1867 * grow the nodeTab if needed
1868 */
1869 if (cur->nodeMax == 0) {
1870 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1871 sizeof(xmlNodePtr));
1872 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001873 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001874 return;
1875 }
1876 memset(cur->nodeTab, 0 ,
1877 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1878 cur->nodeMax = XML_NODESET_DEFAULT;
1879 } else if (cur->nodeNr == cur->nodeMax) {
1880 xmlNodePtr *temp;
1881
1882 cur->nodeMax *= 2;
1883 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1884 sizeof(xmlNodePtr));
1885 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001886 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001887 return;
1888 }
1889 cur->nodeTab = temp;
1890 }
1891 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1892}
1893
1894/**
Owen Taylor3473f882001-02-23 17:55:21 +00001895 * xmlXPathNodeSetAdd:
1896 * @cur: the initial node set
1897 * @val: a new xmlNodePtr
1898 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001899 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001900 */
1901void
1902xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1903 int i;
1904
Daniel Veillarda82b1822004-11-08 16:24:57 +00001905 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001906
Daniel Veillardef0b4502003-03-24 13:57:34 +00001907#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001908 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1909 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001910#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001911
William M. Brack08171912003-12-29 02:52:11 +00001912 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001913 /*
William M. Brack08171912003-12-29 02:52:11 +00001914 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00001915 */
1916 for (i = 0;i < cur->nodeNr;i++)
1917 if (cur->nodeTab[i] == val) return;
1918
1919 /*
1920 * grow the nodeTab if needed
1921 */
1922 if (cur->nodeMax == 0) {
1923 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1924 sizeof(xmlNodePtr));
1925 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001926 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001927 return;
1928 }
1929 memset(cur->nodeTab, 0 ,
1930 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1931 cur->nodeMax = XML_NODESET_DEFAULT;
1932 } else if (cur->nodeNr == cur->nodeMax) {
1933 xmlNodePtr *temp;
1934
1935 cur->nodeMax *= 2;
1936 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1937 sizeof(xmlNodePtr));
1938 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001939 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001940 return;
1941 }
1942 cur->nodeTab = temp;
1943 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001944 if (val->type == XML_NAMESPACE_DECL) {
1945 xmlNsPtr ns = (xmlNsPtr) val;
1946
1947 cur->nodeTab[cur->nodeNr++] =
1948 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1949 } else
1950 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001951}
1952
1953/**
1954 * xmlXPathNodeSetAddUnique:
1955 * @cur: the initial node set
1956 * @val: a new xmlNodePtr
1957 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001958 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001959 * when we are sure the node is not already in the set.
1960 */
1961void
1962xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00001963 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001964
Daniel Veillardef0b4502003-03-24 13:57:34 +00001965#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001966 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1967 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001968#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001969
William M. Brack08171912003-12-29 02:52:11 +00001970 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001971 /*
1972 * grow the nodeTab if needed
1973 */
1974 if (cur->nodeMax == 0) {
1975 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1976 sizeof(xmlNodePtr));
1977 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001978 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001979 return;
1980 }
1981 memset(cur->nodeTab, 0 ,
1982 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1983 cur->nodeMax = XML_NODESET_DEFAULT;
1984 } else if (cur->nodeNr == cur->nodeMax) {
1985 xmlNodePtr *temp;
1986
1987 cur->nodeMax *= 2;
1988 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1989 sizeof(xmlNodePtr));
1990 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001991 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001992 return;
1993 }
1994 cur->nodeTab = temp;
1995 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001996 if (val->type == XML_NAMESPACE_DECL) {
1997 xmlNsPtr ns = (xmlNsPtr) val;
1998
1999 cur->nodeTab[cur->nodeNr++] =
2000 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2001 } else
2002 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00002003}
2004
2005/**
2006 * xmlXPathNodeSetMerge:
2007 * @val1: the first NodeSet or NULL
2008 * @val2: the second NodeSet
2009 *
2010 * Merges two nodesets, all nodes from @val2 are added to @val1
2011 * if @val1 is NULL, a new set is created and copied from @val2
2012 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002013 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002014 */
2015xmlNodeSetPtr
2016xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002017 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00002018
2019 if (val2 == NULL) return(val1);
2020 if (val1 == NULL) {
2021 val1 = xmlXPathNodeSetCreate(NULL);
2022 }
2023
William M. Brack08171912003-12-29 02:52:11 +00002024 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002025 initNr = val1->nodeNr;
2026
2027 for (i = 0;i < val2->nodeNr;i++) {
2028 /*
William M. Brack08171912003-12-29 02:52:11 +00002029 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00002030 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002031 skip = 0;
2032 for (j = 0; j < initNr; j++) {
2033 if (val1->nodeTab[j] == val2->nodeTab[i]) {
2034 skip = 1;
2035 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002036 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
2037 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
2038 xmlNsPtr ns1, ns2;
2039 ns1 = (xmlNsPtr) val1->nodeTab[j];
2040 ns2 = (xmlNsPtr) val2->nodeTab[i];
2041 if ((ns1->next == ns2->next) &&
2042 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
2043 skip = 1;
2044 break;
2045 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002046 }
2047 }
2048 if (skip)
2049 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00002050
2051 /*
2052 * grow the nodeTab if needed
2053 */
2054 if (val1->nodeMax == 0) {
2055 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2056 sizeof(xmlNodePtr));
2057 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002058 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002059 return(NULL);
2060 }
2061 memset(val1->nodeTab, 0 ,
2062 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2063 val1->nodeMax = XML_NODESET_DEFAULT;
2064 } else if (val1->nodeNr == val1->nodeMax) {
2065 xmlNodePtr *temp;
2066
2067 val1->nodeMax *= 2;
2068 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2069 sizeof(xmlNodePtr));
2070 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002071 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002072 return(NULL);
2073 }
2074 val1->nodeTab = temp;
2075 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002076 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2077 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2078
2079 val1->nodeTab[val1->nodeNr++] =
2080 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2081 } else
2082 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002083 }
2084
2085 return(val1);
2086}
2087
2088/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002089 * xmlXPathNodeSetMergeUnique:
2090 * @val1: the first NodeSet or NULL
2091 * @val2: the second NodeSet
2092 *
2093 * Merges two nodesets, all nodes from @val2 are added to @val1
2094 * if @val1 is NULL, a new set is created and copied from @val2
2095 *
2096 * Returns @val1 once extended or NULL in case of error.
2097 */
2098static xmlNodeSetPtr
2099xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002100 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002101
2102 if (val2 == NULL) return(val1);
2103 if (val1 == NULL) {
2104 val1 = xmlXPathNodeSetCreate(NULL);
2105 }
2106
William M. Brack08171912003-12-29 02:52:11 +00002107 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002108
2109 for (i = 0;i < val2->nodeNr;i++) {
2110 /*
2111 * grow the nodeTab if needed
2112 */
2113 if (val1->nodeMax == 0) {
2114 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2115 sizeof(xmlNodePtr));
2116 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002117 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002118 return(NULL);
2119 }
2120 memset(val1->nodeTab, 0 ,
2121 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2122 val1->nodeMax = XML_NODESET_DEFAULT;
2123 } else if (val1->nodeNr == val1->nodeMax) {
2124 xmlNodePtr *temp;
2125
2126 val1->nodeMax *= 2;
2127 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2128 sizeof(xmlNodePtr));
2129 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002130 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002131 return(NULL);
2132 }
2133 val1->nodeTab = temp;
2134 }
2135 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2136 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2137
2138 val1->nodeTab[val1->nodeNr++] =
2139 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2140 } else
2141 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2142 }
2143
2144 return(val1);
2145}
2146
2147/**
Owen Taylor3473f882001-02-23 17:55:21 +00002148 * xmlXPathNodeSetDel:
2149 * @cur: the initial node set
2150 * @val: an xmlNodePtr
2151 *
2152 * Removes an xmlNodePtr from an existing NodeSet
2153 */
2154void
2155xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2156 int i;
2157
2158 if (cur == NULL) return;
2159 if (val == NULL) return;
2160
2161 /*
William M. Brack08171912003-12-29 02:52:11 +00002162 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002163 */
2164 for (i = 0;i < cur->nodeNr;i++)
2165 if (cur->nodeTab[i] == val) break;
2166
William M. Brack08171912003-12-29 02:52:11 +00002167 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002168#ifdef DEBUG
2169 xmlGenericError(xmlGenericErrorContext,
2170 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2171 val->name);
2172#endif
2173 return;
2174 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002175 if ((cur->nodeTab[i] != NULL) &&
2176 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2177 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002178 cur->nodeNr--;
2179 for (;i < cur->nodeNr;i++)
2180 cur->nodeTab[i] = cur->nodeTab[i + 1];
2181 cur->nodeTab[cur->nodeNr] = NULL;
2182}
2183
2184/**
2185 * xmlXPathNodeSetRemove:
2186 * @cur: the initial node set
2187 * @val: the index to remove
2188 *
2189 * Removes an entry from an existing NodeSet list.
2190 */
2191void
2192xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2193 if (cur == NULL) return;
2194 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002195 if ((cur->nodeTab[val] != NULL) &&
2196 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2197 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002198 cur->nodeNr--;
2199 for (;val < cur->nodeNr;val++)
2200 cur->nodeTab[val] = cur->nodeTab[val + 1];
2201 cur->nodeTab[cur->nodeNr] = NULL;
2202}
2203
2204/**
2205 * xmlXPathFreeNodeSet:
2206 * @obj: the xmlNodeSetPtr to free
2207 *
2208 * Free the NodeSet compound (not the actual nodes !).
2209 */
2210void
2211xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2212 if (obj == NULL) return;
2213 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002214 int i;
2215
William M. Brack08171912003-12-29 02:52:11 +00002216 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002217 for (i = 0;i < obj->nodeNr;i++)
2218 if ((obj->nodeTab[i] != NULL) &&
2219 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2220 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002221 xmlFree(obj->nodeTab);
2222 }
Owen Taylor3473f882001-02-23 17:55:21 +00002223 xmlFree(obj);
2224}
2225
2226/**
2227 * xmlXPathFreeValueTree:
2228 * @obj: the xmlNodeSetPtr to free
2229 *
2230 * Free the NodeSet compound and the actual tree, this is different
2231 * from xmlXPathFreeNodeSet()
2232 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002233static void
Owen Taylor3473f882001-02-23 17:55:21 +00002234xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2235 int i;
2236
2237 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002238
2239 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002240 for (i = 0;i < obj->nodeNr;i++) {
2241 if (obj->nodeTab[i] != NULL) {
2242 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2243 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2244 } else {
2245 xmlFreeNodeList(obj->nodeTab[i]);
2246 }
2247 }
2248 }
Owen Taylor3473f882001-02-23 17:55:21 +00002249 xmlFree(obj->nodeTab);
2250 }
Owen Taylor3473f882001-02-23 17:55:21 +00002251 xmlFree(obj);
2252}
2253
2254#if defined(DEBUG) || defined(DEBUG_STEP)
2255/**
2256 * xmlGenericErrorContextNodeSet:
2257 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002258 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002259 *
2260 * Quick display of a NodeSet
2261 */
2262void
2263xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2264 int i;
2265
2266 if (output == NULL) output = xmlGenericErrorContext;
2267 if (obj == NULL) {
2268 fprintf(output, "NodeSet == NULL !\n");
2269 return;
2270 }
2271 if (obj->nodeNr == 0) {
2272 fprintf(output, "NodeSet is empty\n");
2273 return;
2274 }
2275 if (obj->nodeTab == NULL) {
2276 fprintf(output, " nodeTab == NULL !\n");
2277 return;
2278 }
2279 for (i = 0; i < obj->nodeNr; i++) {
2280 if (obj->nodeTab[i] == NULL) {
2281 fprintf(output, " NULL !\n");
2282 return;
2283 }
2284 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2285 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2286 fprintf(output, " /");
2287 else if (obj->nodeTab[i]->name == NULL)
2288 fprintf(output, " noname!");
2289 else fprintf(output, " %s", obj->nodeTab[i]->name);
2290 }
2291 fprintf(output, "\n");
2292}
2293#endif
2294
2295/**
2296 * xmlXPathNewNodeSet:
2297 * @val: the NodePtr value
2298 *
2299 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2300 * it with the single Node @val
2301 *
2302 * Returns the newly created object.
2303 */
2304xmlXPathObjectPtr
2305xmlXPathNewNodeSet(xmlNodePtr val) {
2306 xmlXPathObjectPtr ret;
2307
2308 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2309 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002310 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002311 return(NULL);
2312 }
2313 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2314 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002315 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002316 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002317 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002318 return(ret);
2319}
2320
2321/**
2322 * xmlXPathNewValueTree:
2323 * @val: the NodePtr value
2324 *
2325 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2326 * it with the tree root @val
2327 *
2328 * Returns the newly created object.
2329 */
2330xmlXPathObjectPtr
2331xmlXPathNewValueTree(xmlNodePtr val) {
2332 xmlXPathObjectPtr ret;
2333
2334 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2335 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002336 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002337 return(NULL);
2338 }
2339 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2340 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002341 ret->boolval = 1;
2342 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002343 ret->nodesetval = xmlXPathNodeSetCreate(val);
2344 return(ret);
2345}
2346
2347/**
2348 * xmlXPathNewNodeSetList:
2349 * @val: an existing NodeSet
2350 *
2351 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2352 * it with the Nodeset @val
2353 *
2354 * Returns the newly created object.
2355 */
2356xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002357xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2358{
Owen Taylor3473f882001-02-23 17:55:21 +00002359 xmlXPathObjectPtr ret;
2360 int i;
2361
2362 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002363 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002364 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002365 ret = xmlXPathNewNodeSet(NULL);
2366 else {
2367 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2368 for (i = 1; i < val->nodeNr; ++i)
2369 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2370 }
Owen Taylor3473f882001-02-23 17:55:21 +00002371
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002372 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002373}
2374
2375/**
2376 * xmlXPathWrapNodeSet:
2377 * @val: the NodePtr value
2378 *
2379 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2380 *
2381 * Returns the newly created object.
2382 */
2383xmlXPathObjectPtr
2384xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2385 xmlXPathObjectPtr ret;
2386
2387 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2388 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002389 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002390 return(NULL);
2391 }
2392 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2393 ret->type = XPATH_NODESET;
2394 ret->nodesetval = val;
2395 return(ret);
2396}
2397
2398/**
2399 * xmlXPathFreeNodeSetList:
2400 * @obj: an existing NodeSetList object
2401 *
2402 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2403 * the list contrary to xmlXPathFreeObject().
2404 */
2405void
2406xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2407 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002408 xmlFree(obj);
2409}
2410
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002411/**
2412 * xmlXPathDifference:
2413 * @nodes1: a node-set
2414 * @nodes2: a node-set
2415 *
2416 * Implements the EXSLT - Sets difference() function:
2417 * node-set set:difference (node-set, node-set)
2418 *
2419 * Returns the difference between the two node sets, or nodes1 if
2420 * nodes2 is empty
2421 */
2422xmlNodeSetPtr
2423xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2424 xmlNodeSetPtr ret;
2425 int i, l1;
2426 xmlNodePtr cur;
2427
2428 if (xmlXPathNodeSetIsEmpty(nodes2))
2429 return(nodes1);
2430
2431 ret = xmlXPathNodeSetCreate(NULL);
2432 if (xmlXPathNodeSetIsEmpty(nodes1))
2433 return(ret);
2434
2435 l1 = xmlXPathNodeSetGetLength(nodes1);
2436
2437 for (i = 0; i < l1; i++) {
2438 cur = xmlXPathNodeSetItem(nodes1, i);
2439 if (!xmlXPathNodeSetContains(nodes2, cur))
2440 xmlXPathNodeSetAddUnique(ret, cur);
2441 }
2442 return(ret);
2443}
2444
2445/**
2446 * xmlXPathIntersection:
2447 * @nodes1: a node-set
2448 * @nodes2: a node-set
2449 *
2450 * Implements the EXSLT - Sets intersection() function:
2451 * node-set set:intersection (node-set, node-set)
2452 *
2453 * Returns a node set comprising the nodes that are within both the
2454 * node sets passed as arguments
2455 */
2456xmlNodeSetPtr
2457xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2458 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2459 int i, l1;
2460 xmlNodePtr cur;
2461
2462 if (xmlXPathNodeSetIsEmpty(nodes1))
2463 return(ret);
2464 if (xmlXPathNodeSetIsEmpty(nodes2))
2465 return(ret);
2466
2467 l1 = xmlXPathNodeSetGetLength(nodes1);
2468
2469 for (i = 0; i < l1; i++) {
2470 cur = xmlXPathNodeSetItem(nodes1, i);
2471 if (xmlXPathNodeSetContains(nodes2, cur))
2472 xmlXPathNodeSetAddUnique(ret, cur);
2473 }
2474 return(ret);
2475}
2476
2477/**
2478 * xmlXPathDistinctSorted:
2479 * @nodes: a node-set, sorted by document order
2480 *
2481 * Implements the EXSLT - Sets distinct() function:
2482 * node-set set:distinct (node-set)
2483 *
2484 * Returns a subset of the nodes contained in @nodes, or @nodes if
2485 * it is empty
2486 */
2487xmlNodeSetPtr
2488xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2489 xmlNodeSetPtr ret;
2490 xmlHashTablePtr hash;
2491 int i, l;
2492 xmlChar * strval;
2493 xmlNodePtr cur;
2494
2495 if (xmlXPathNodeSetIsEmpty(nodes))
2496 return(nodes);
2497
2498 ret = xmlXPathNodeSetCreate(NULL);
2499 l = xmlXPathNodeSetGetLength(nodes);
2500 hash = xmlHashCreate (l);
2501 for (i = 0; i < l; i++) {
2502 cur = xmlXPathNodeSetItem(nodes, i);
2503 strval = xmlXPathCastNodeToString(cur);
2504 if (xmlHashLookup(hash, strval) == NULL) {
2505 xmlHashAddEntry(hash, strval, strval);
2506 xmlXPathNodeSetAddUnique(ret, cur);
2507 } else {
2508 xmlFree(strval);
2509 }
2510 }
2511 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2512 return(ret);
2513}
2514
2515/**
2516 * xmlXPathDistinct:
2517 * @nodes: a node-set
2518 *
2519 * Implements the EXSLT - Sets distinct() function:
2520 * node-set set:distinct (node-set)
2521 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2522 * is called with the sorted node-set
2523 *
2524 * Returns a subset of the nodes contained in @nodes, or @nodes if
2525 * it is empty
2526 */
2527xmlNodeSetPtr
2528xmlXPathDistinct (xmlNodeSetPtr nodes) {
2529 if (xmlXPathNodeSetIsEmpty(nodes))
2530 return(nodes);
2531
2532 xmlXPathNodeSetSort(nodes);
2533 return(xmlXPathDistinctSorted(nodes));
2534}
2535
2536/**
2537 * xmlXPathHasSameNodes:
2538 * @nodes1: a node-set
2539 * @nodes2: a node-set
2540 *
2541 * Implements the EXSLT - Sets has-same-nodes function:
2542 * boolean set:has-same-node(node-set, node-set)
2543 *
2544 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2545 * otherwise
2546 */
2547int
2548xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2549 int i, l;
2550 xmlNodePtr cur;
2551
2552 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2553 xmlXPathNodeSetIsEmpty(nodes2))
2554 return(0);
2555
2556 l = xmlXPathNodeSetGetLength(nodes1);
2557 for (i = 0; i < l; i++) {
2558 cur = xmlXPathNodeSetItem(nodes1, i);
2559 if (xmlXPathNodeSetContains(nodes2, cur))
2560 return(1);
2561 }
2562 return(0);
2563}
2564
2565/**
2566 * xmlXPathNodeLeadingSorted:
2567 * @nodes: a node-set, sorted by document order
2568 * @node: a node
2569 *
2570 * Implements the EXSLT - Sets leading() function:
2571 * node-set set:leading (node-set, node-set)
2572 *
2573 * Returns the nodes in @nodes that precede @node in document order,
2574 * @nodes if @node is NULL or an empty node-set if @nodes
2575 * doesn't contain @node
2576 */
2577xmlNodeSetPtr
2578xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2579 int i, l;
2580 xmlNodePtr cur;
2581 xmlNodeSetPtr ret;
2582
2583 if (node == NULL)
2584 return(nodes);
2585
2586 ret = xmlXPathNodeSetCreate(NULL);
2587 if (xmlXPathNodeSetIsEmpty(nodes) ||
2588 (!xmlXPathNodeSetContains(nodes, node)))
2589 return(ret);
2590
2591 l = xmlXPathNodeSetGetLength(nodes);
2592 for (i = 0; i < l; i++) {
2593 cur = xmlXPathNodeSetItem(nodes, i);
2594 if (cur == node)
2595 break;
2596 xmlXPathNodeSetAddUnique(ret, cur);
2597 }
2598 return(ret);
2599}
2600
2601/**
2602 * xmlXPathNodeLeading:
2603 * @nodes: a node-set
2604 * @node: a node
2605 *
2606 * Implements the EXSLT - Sets leading() function:
2607 * node-set set:leading (node-set, node-set)
2608 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2609 * is called.
2610 *
2611 * Returns the nodes in @nodes that precede @node in document order,
2612 * @nodes if @node is NULL or an empty node-set if @nodes
2613 * doesn't contain @node
2614 */
2615xmlNodeSetPtr
2616xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2617 xmlXPathNodeSetSort(nodes);
2618 return(xmlXPathNodeLeadingSorted(nodes, node));
2619}
2620
2621/**
2622 * xmlXPathLeadingSorted:
2623 * @nodes1: a node-set, sorted by document order
2624 * @nodes2: a node-set, sorted by document order
2625 *
2626 * Implements the EXSLT - Sets leading() function:
2627 * node-set set:leading (node-set, node-set)
2628 *
2629 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2630 * in document order, @nodes1 if @nodes2 is NULL or empty or
2631 * an empty node-set if @nodes1 doesn't contain @nodes2
2632 */
2633xmlNodeSetPtr
2634xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2635 if (xmlXPathNodeSetIsEmpty(nodes2))
2636 return(nodes1);
2637 return(xmlXPathNodeLeadingSorted(nodes1,
2638 xmlXPathNodeSetItem(nodes2, 1)));
2639}
2640
2641/**
2642 * xmlXPathLeading:
2643 * @nodes1: a node-set
2644 * @nodes2: a node-set
2645 *
2646 * Implements the EXSLT - Sets leading() function:
2647 * node-set set:leading (node-set, node-set)
2648 * @nodes1 and @nodes2 are sorted by document order, then
2649 * #exslSetsLeadingSorted is called.
2650 *
2651 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2652 * in document order, @nodes1 if @nodes2 is NULL or empty or
2653 * an empty node-set if @nodes1 doesn't contain @nodes2
2654 */
2655xmlNodeSetPtr
2656xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2657 if (xmlXPathNodeSetIsEmpty(nodes2))
2658 return(nodes1);
2659 if (xmlXPathNodeSetIsEmpty(nodes1))
2660 return(xmlXPathNodeSetCreate(NULL));
2661 xmlXPathNodeSetSort(nodes1);
2662 xmlXPathNodeSetSort(nodes2);
2663 return(xmlXPathNodeLeadingSorted(nodes1,
2664 xmlXPathNodeSetItem(nodes2, 1)));
2665}
2666
2667/**
2668 * xmlXPathNodeTrailingSorted:
2669 * @nodes: a node-set, sorted by document order
2670 * @node: a node
2671 *
2672 * Implements the EXSLT - Sets trailing() function:
2673 * node-set set:trailing (node-set, node-set)
2674 *
2675 * Returns the nodes in @nodes that follow @node in document order,
2676 * @nodes if @node is NULL or an empty node-set if @nodes
2677 * doesn't contain @node
2678 */
2679xmlNodeSetPtr
2680xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2681 int i, l;
2682 xmlNodePtr cur;
2683 xmlNodeSetPtr ret;
2684
2685 if (node == NULL)
2686 return(nodes);
2687
2688 ret = xmlXPathNodeSetCreate(NULL);
2689 if (xmlXPathNodeSetIsEmpty(nodes) ||
2690 (!xmlXPathNodeSetContains(nodes, node)))
2691 return(ret);
2692
2693 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002694 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002695 cur = xmlXPathNodeSetItem(nodes, i);
2696 if (cur == node)
2697 break;
2698 xmlXPathNodeSetAddUnique(ret, cur);
2699 }
2700 return(ret);
2701}
2702
2703/**
2704 * xmlXPathNodeTrailing:
2705 * @nodes: a node-set
2706 * @node: a node
2707 *
2708 * Implements the EXSLT - Sets trailing() function:
2709 * node-set set:trailing (node-set, node-set)
2710 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2711 * is called.
2712 *
2713 * Returns the nodes in @nodes that follow @node in document order,
2714 * @nodes if @node is NULL or an empty node-set if @nodes
2715 * doesn't contain @node
2716 */
2717xmlNodeSetPtr
2718xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2719 xmlXPathNodeSetSort(nodes);
2720 return(xmlXPathNodeTrailingSorted(nodes, node));
2721}
2722
2723/**
2724 * xmlXPathTrailingSorted:
2725 * @nodes1: a node-set, sorted by document order
2726 * @nodes2: a node-set, sorted by document order
2727 *
2728 * Implements the EXSLT - Sets trailing() function:
2729 * node-set set:trailing (node-set, node-set)
2730 *
2731 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2732 * in document order, @nodes1 if @nodes2 is NULL or empty or
2733 * an empty node-set if @nodes1 doesn't contain @nodes2
2734 */
2735xmlNodeSetPtr
2736xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2737 if (xmlXPathNodeSetIsEmpty(nodes2))
2738 return(nodes1);
2739 return(xmlXPathNodeTrailingSorted(nodes1,
2740 xmlXPathNodeSetItem(nodes2, 0)));
2741}
2742
2743/**
2744 * xmlXPathTrailing:
2745 * @nodes1: a node-set
2746 * @nodes2: a node-set
2747 *
2748 * Implements the EXSLT - Sets trailing() function:
2749 * node-set set:trailing (node-set, node-set)
2750 * @nodes1 and @nodes2 are sorted by document order, then
2751 * #xmlXPathTrailingSorted is called.
2752 *
2753 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2754 * in document order, @nodes1 if @nodes2 is NULL or empty or
2755 * an empty node-set if @nodes1 doesn't contain @nodes2
2756 */
2757xmlNodeSetPtr
2758xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2759 if (xmlXPathNodeSetIsEmpty(nodes2))
2760 return(nodes1);
2761 if (xmlXPathNodeSetIsEmpty(nodes1))
2762 return(xmlXPathNodeSetCreate(NULL));
2763 xmlXPathNodeSetSort(nodes1);
2764 xmlXPathNodeSetSort(nodes2);
2765 return(xmlXPathNodeTrailingSorted(nodes1,
2766 xmlXPathNodeSetItem(nodes2, 0)));
2767}
2768
Owen Taylor3473f882001-02-23 17:55:21 +00002769/************************************************************************
2770 * *
2771 * Routines to handle extra functions *
2772 * *
2773 ************************************************************************/
2774
2775/**
2776 * xmlXPathRegisterFunc:
2777 * @ctxt: the XPath context
2778 * @name: the function name
2779 * @f: the function implementation or NULL
2780 *
2781 * Register a new function. If @f is NULL it unregisters the function
2782 *
2783 * Returns 0 in case of success, -1 in case of error
2784 */
2785int
2786xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2787 xmlXPathFunction f) {
2788 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2789}
2790
2791/**
2792 * xmlXPathRegisterFuncNS:
2793 * @ctxt: the XPath context
2794 * @name: the function name
2795 * @ns_uri: the function namespace URI
2796 * @f: the function implementation or NULL
2797 *
2798 * Register a new function. If @f is NULL it unregisters the function
2799 *
2800 * Returns 0 in case of success, -1 in case of error
2801 */
2802int
2803xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2804 const xmlChar *ns_uri, xmlXPathFunction f) {
2805 if (ctxt == NULL)
2806 return(-1);
2807 if (name == NULL)
2808 return(-1);
2809
2810 if (ctxt->funcHash == NULL)
2811 ctxt->funcHash = xmlHashCreate(0);
2812 if (ctxt->funcHash == NULL)
2813 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002814 if (f == NULL)
2815 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00002816 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00002817}
2818
2819/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002820 * xmlXPathRegisterFuncLookup:
2821 * @ctxt: the XPath context
2822 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002823 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002824 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002825 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002826 */
2827void
2828xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2829 xmlXPathFuncLookupFunc f,
2830 void *funcCtxt) {
2831 if (ctxt == NULL)
2832 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002833 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002834 ctxt->funcLookupData = funcCtxt;
2835}
2836
2837/**
Owen Taylor3473f882001-02-23 17:55:21 +00002838 * xmlXPathFunctionLookup:
2839 * @ctxt: the XPath context
2840 * @name: the function name
2841 *
2842 * Search in the Function array of the context for the given
2843 * function.
2844 *
2845 * Returns the xmlXPathFunction or NULL if not found
2846 */
2847xmlXPathFunction
2848xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002849 if (ctxt == NULL)
2850 return (NULL);
2851
2852 if (ctxt->funcLookupFunc != NULL) {
2853 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002854 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002855
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002856 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002857 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002858 if (ret != NULL)
2859 return(ret);
2860 }
Owen Taylor3473f882001-02-23 17:55:21 +00002861 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2862}
2863
2864/**
2865 * xmlXPathFunctionLookupNS:
2866 * @ctxt: the XPath context
2867 * @name: the function name
2868 * @ns_uri: the function namespace URI
2869 *
2870 * Search in the Function array of the context for the given
2871 * function.
2872 *
2873 * Returns the xmlXPathFunction or NULL if not found
2874 */
2875xmlXPathFunction
2876xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2877 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00002878 xmlXPathFunction ret;
2879
Owen Taylor3473f882001-02-23 17:55:21 +00002880 if (ctxt == NULL)
2881 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002882 if (name == NULL)
2883 return(NULL);
2884
Thomas Broyerba4ad322001-07-26 16:55:21 +00002885 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002886 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002887
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002888 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002889 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002890 if (ret != NULL)
2891 return(ret);
2892 }
2893
2894 if (ctxt->funcHash == NULL)
2895 return(NULL);
2896
William M. Brackad0e67c2004-12-01 14:35:10 +00002897 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
2898 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002899}
2900
2901/**
2902 * xmlXPathRegisteredFuncsCleanup:
2903 * @ctxt: the XPath context
2904 *
2905 * Cleanup the XPath context data associated to registered functions
2906 */
2907void
2908xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2909 if (ctxt == NULL)
2910 return;
2911
2912 xmlHashFree(ctxt->funcHash, NULL);
2913 ctxt->funcHash = NULL;
2914}
2915
2916/************************************************************************
2917 * *
William M. Brack08171912003-12-29 02:52:11 +00002918 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00002919 * *
2920 ************************************************************************/
2921
2922/**
2923 * xmlXPathRegisterVariable:
2924 * @ctxt: the XPath context
2925 * @name: the variable name
2926 * @value: the variable value or NULL
2927 *
2928 * Register a new variable value. If @value is NULL it unregisters
2929 * the variable
2930 *
2931 * Returns 0 in case of success, -1 in case of error
2932 */
2933int
2934xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2935 xmlXPathObjectPtr value) {
2936 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2937}
2938
2939/**
2940 * xmlXPathRegisterVariableNS:
2941 * @ctxt: the XPath context
2942 * @name: the variable name
2943 * @ns_uri: the variable namespace URI
2944 * @value: the variable value or NULL
2945 *
2946 * Register a new variable value. If @value is NULL it unregisters
2947 * the variable
2948 *
2949 * Returns 0 in case of success, -1 in case of error
2950 */
2951int
2952xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2953 const xmlChar *ns_uri,
2954 xmlXPathObjectPtr value) {
2955 if (ctxt == NULL)
2956 return(-1);
2957 if (name == NULL)
2958 return(-1);
2959
2960 if (ctxt->varHash == NULL)
2961 ctxt->varHash = xmlHashCreate(0);
2962 if (ctxt->varHash == NULL)
2963 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002964 if (value == NULL)
2965 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2966 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002967 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2968 (void *) value,
2969 (xmlHashDeallocator)xmlXPathFreeObject));
2970}
2971
2972/**
2973 * xmlXPathRegisterVariableLookup:
2974 * @ctxt: the XPath context
2975 * @f: the lookup function
2976 * @data: the lookup data
2977 *
2978 * register an external mechanism to do variable lookup
2979 */
2980void
2981xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2982 xmlXPathVariableLookupFunc f, void *data) {
2983 if (ctxt == NULL)
2984 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002985 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00002986 ctxt->varLookupData = data;
2987}
2988
2989/**
2990 * xmlXPathVariableLookup:
2991 * @ctxt: the XPath context
2992 * @name: the variable name
2993 *
2994 * Search in the Variable array of the context for the given
2995 * variable value.
2996 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002997 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002998 */
2999xmlXPathObjectPtr
3000xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3001 if (ctxt == NULL)
3002 return(NULL);
3003
3004 if (ctxt->varLookupFunc != NULL) {
3005 xmlXPathObjectPtr ret;
3006
3007 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3008 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00003009 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003010 }
3011 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3012}
3013
3014/**
3015 * xmlXPathVariableLookupNS:
3016 * @ctxt: the XPath context
3017 * @name: the variable name
3018 * @ns_uri: the variable namespace URI
3019 *
3020 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00003021 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00003022 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003023 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003024 */
3025xmlXPathObjectPtr
3026xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3027 const xmlChar *ns_uri) {
3028 if (ctxt == NULL)
3029 return(NULL);
3030
3031 if (ctxt->varLookupFunc != NULL) {
3032 xmlXPathObjectPtr ret;
3033
3034 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3035 (ctxt->varLookupData, name, ns_uri);
3036 if (ret != NULL) return(ret);
3037 }
3038
3039 if (ctxt->varHash == NULL)
3040 return(NULL);
3041 if (name == NULL)
3042 return(NULL);
3043
Daniel Veillard8c357d52001-07-03 23:43:33 +00003044 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3045 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00003046}
3047
3048/**
3049 * xmlXPathRegisteredVariablesCleanup:
3050 * @ctxt: the XPath context
3051 *
3052 * Cleanup the XPath context data associated to registered variables
3053 */
3054void
3055xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3056 if (ctxt == NULL)
3057 return;
3058
Daniel Veillard76d66f42001-05-16 21:05:17 +00003059 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00003060 ctxt->varHash = NULL;
3061}
3062
3063/**
3064 * xmlXPathRegisterNs:
3065 * @ctxt: the XPath context
3066 * @prefix: the namespace prefix
3067 * @ns_uri: the namespace name
3068 *
3069 * Register a new namespace. If @ns_uri is NULL it unregisters
3070 * the namespace
3071 *
3072 * Returns 0 in case of success, -1 in case of error
3073 */
3074int
3075xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3076 const xmlChar *ns_uri) {
3077 if (ctxt == NULL)
3078 return(-1);
3079 if (prefix == NULL)
3080 return(-1);
3081
3082 if (ctxt->nsHash == NULL)
3083 ctxt->nsHash = xmlHashCreate(10);
3084 if (ctxt->nsHash == NULL)
3085 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003086 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003087 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003088 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003089 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003090 (xmlHashDeallocator)xmlFree));
3091}
3092
3093/**
3094 * xmlXPathNsLookup:
3095 * @ctxt: the XPath context
3096 * @prefix: the namespace prefix value
3097 *
3098 * Search in the namespace declaration array of the context for the given
3099 * namespace name associated to the given prefix
3100 *
3101 * Returns the value or NULL if not found
3102 */
3103const xmlChar *
3104xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3105 if (ctxt == NULL)
3106 return(NULL);
3107 if (prefix == NULL)
3108 return(NULL);
3109
3110#ifdef XML_XML_NAMESPACE
3111 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3112 return(XML_XML_NAMESPACE);
3113#endif
3114
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003115 if (ctxt->namespaces != NULL) {
3116 int i;
3117
3118 for (i = 0;i < ctxt->nsNr;i++) {
3119 if ((ctxt->namespaces[i] != NULL) &&
3120 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3121 return(ctxt->namespaces[i]->href);
3122 }
3123 }
Owen Taylor3473f882001-02-23 17:55:21 +00003124
3125 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3126}
3127
3128/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003129 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003130 * @ctxt: the XPath context
3131 *
3132 * Cleanup the XPath context data associated to registered variables
3133 */
3134void
3135xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3136 if (ctxt == NULL)
3137 return;
3138
Daniel Veillard42766c02002-08-22 20:52:17 +00003139 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003140 ctxt->nsHash = NULL;
3141}
3142
3143/************************************************************************
3144 * *
3145 * Routines to handle Values *
3146 * *
3147 ************************************************************************/
3148
William M. Brack08171912003-12-29 02:52:11 +00003149/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003150
3151/**
3152 * xmlXPathNewFloat:
3153 * @val: the double value
3154 *
3155 * Create a new xmlXPathObjectPtr of type double and of value @val
3156 *
3157 * Returns the newly created object.
3158 */
3159xmlXPathObjectPtr
3160xmlXPathNewFloat(double val) {
3161 xmlXPathObjectPtr ret;
3162
3163 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3164 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003165 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003166 return(NULL);
3167 }
3168 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3169 ret->type = XPATH_NUMBER;
3170 ret->floatval = val;
3171 return(ret);
3172}
3173
3174/**
3175 * xmlXPathNewBoolean:
3176 * @val: the boolean value
3177 *
3178 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3179 *
3180 * Returns the newly created object.
3181 */
3182xmlXPathObjectPtr
3183xmlXPathNewBoolean(int val) {
3184 xmlXPathObjectPtr ret;
3185
3186 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3187 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003188 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003189 return(NULL);
3190 }
3191 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3192 ret->type = XPATH_BOOLEAN;
3193 ret->boolval = (val != 0);
3194 return(ret);
3195}
3196
3197/**
3198 * xmlXPathNewString:
3199 * @val: the xmlChar * value
3200 *
3201 * Create a new xmlXPathObjectPtr of type string and of value @val
3202 *
3203 * Returns the newly created object.
3204 */
3205xmlXPathObjectPtr
3206xmlXPathNewString(const xmlChar *val) {
3207 xmlXPathObjectPtr ret;
3208
3209 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3210 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003211 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003212 return(NULL);
3213 }
3214 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3215 ret->type = XPATH_STRING;
3216 if (val != NULL)
3217 ret->stringval = xmlStrdup(val);
3218 else
3219 ret->stringval = xmlStrdup((const xmlChar *)"");
3220 return(ret);
3221}
3222
3223/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003224 * xmlXPathWrapString:
3225 * @val: the xmlChar * value
3226 *
3227 * Wraps the @val string into an XPath object.
3228 *
3229 * Returns the newly created object.
3230 */
3231xmlXPathObjectPtr
3232xmlXPathWrapString (xmlChar *val) {
3233 xmlXPathObjectPtr ret;
3234
3235 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3236 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003237 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003238 return(NULL);
3239 }
3240 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3241 ret->type = XPATH_STRING;
3242 ret->stringval = val;
3243 return(ret);
3244}
3245
3246/**
Owen Taylor3473f882001-02-23 17:55:21 +00003247 * xmlXPathNewCString:
3248 * @val: the char * value
3249 *
3250 * Create a new xmlXPathObjectPtr of type string and of value @val
3251 *
3252 * Returns the newly created object.
3253 */
3254xmlXPathObjectPtr
3255xmlXPathNewCString(const char *val) {
3256 xmlXPathObjectPtr ret;
3257
3258 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3259 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003260 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003261 return(NULL);
3262 }
3263 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3264 ret->type = XPATH_STRING;
3265 ret->stringval = xmlStrdup(BAD_CAST val);
3266 return(ret);
3267}
3268
3269/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003270 * xmlXPathWrapCString:
3271 * @val: the char * value
3272 *
3273 * Wraps a string into an XPath object.
3274 *
3275 * Returns the newly created object.
3276 */
3277xmlXPathObjectPtr
3278xmlXPathWrapCString (char * val) {
3279 return(xmlXPathWrapString((xmlChar *)(val)));
3280}
3281
3282/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003283 * xmlXPathWrapExternal:
3284 * @val: the user data
3285 *
3286 * Wraps the @val data into an XPath object.
3287 *
3288 * Returns the newly created object.
3289 */
3290xmlXPathObjectPtr
3291xmlXPathWrapExternal (void *val) {
3292 xmlXPathObjectPtr ret;
3293
3294 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3295 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003296 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003297 return(NULL);
3298 }
3299 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3300 ret->type = XPATH_USERS;
3301 ret->user = val;
3302 return(ret);
3303}
3304
3305/**
Owen Taylor3473f882001-02-23 17:55:21 +00003306 * xmlXPathObjectCopy:
3307 * @val: the original object
3308 *
3309 * allocate a new copy of a given object
3310 *
3311 * Returns the newly created object.
3312 */
3313xmlXPathObjectPtr
3314xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3315 xmlXPathObjectPtr ret;
3316
3317 if (val == NULL)
3318 return(NULL);
3319
3320 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3321 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003322 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003323 return(NULL);
3324 }
3325 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3326 switch (val->type) {
3327 case XPATH_BOOLEAN:
3328 case XPATH_NUMBER:
3329 case XPATH_POINT:
3330 case XPATH_RANGE:
3331 break;
3332 case XPATH_STRING:
3333 ret->stringval = xmlStrdup(val->stringval);
3334 break;
3335 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00003336#if 0
3337/*
3338 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
3339 this previous handling is no longer correct, and can cause some serious
3340 problems (ref. bug 145547)
3341*/
Owen Taylor3473f882001-02-23 17:55:21 +00003342 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003343 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003344 xmlNodePtr cur, tmp;
3345 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003346
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003347 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003348 top = xmlNewDoc(NULL);
3349 top->name = (char *)
3350 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003351 ret->user = top;
3352 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003353 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003354 cur = val->nodesetval->nodeTab[0]->children;
3355 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003356 tmp = xmlDocCopyNode(cur, top, 1);
3357 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003358 cur = cur->next;
3359 }
3360 }
William M. Bracke9449c52004-07-11 14:41:20 +00003361
Daniel Veillard9adc0462003-03-24 18:39:54 +00003362 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003363 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003364 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003365 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003366 break;
William M. Bracke9449c52004-07-11 14:41:20 +00003367#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003368 case XPATH_NODESET:
3369 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003370 /* Do not deallocate the copied tree value */
3371 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003372 break;
3373 case XPATH_LOCATIONSET:
3374#ifdef LIBXML_XPTR_ENABLED
3375 {
3376 xmlLocationSetPtr loc = val->user;
3377 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3378 break;
3379 }
3380#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003381 case XPATH_USERS:
3382 ret->user = val->user;
3383 break;
3384 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003385 xmlGenericError(xmlGenericErrorContext,
3386 "xmlXPathObjectCopy: unsupported type %d\n",
3387 val->type);
3388 break;
3389 }
3390 return(ret);
3391}
3392
3393/**
3394 * xmlXPathFreeObject:
3395 * @obj: the object to free
3396 *
3397 * Free up an xmlXPathObjectPtr object.
3398 */
3399void
3400xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3401 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003402 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003403 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00003404#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003405 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003406 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003407 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003408 } else
3409#endif
3410 if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003411 xmlXPathFreeValueTree(obj->nodesetval);
3412 } else {
3413 if (obj->nodesetval != NULL)
3414 xmlXPathFreeNodeSet(obj->nodesetval);
3415 }
Owen Taylor3473f882001-02-23 17:55:21 +00003416#ifdef LIBXML_XPTR_ENABLED
3417 } else if (obj->type == XPATH_LOCATIONSET) {
3418 if (obj->user != NULL)
3419 xmlXPtrFreeLocationSet(obj->user);
3420#endif
3421 } else if (obj->type == XPATH_STRING) {
3422 if (obj->stringval != NULL)
3423 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003424 }
3425
Owen Taylor3473f882001-02-23 17:55:21 +00003426 xmlFree(obj);
3427}
3428
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003429
3430/************************************************************************
3431 * *
3432 * Type Casting Routines *
3433 * *
3434 ************************************************************************/
3435
3436/**
3437 * xmlXPathCastBooleanToString:
3438 * @val: a boolean
3439 *
3440 * Converts a boolean to its string value.
3441 *
3442 * Returns a newly allocated string.
3443 */
3444xmlChar *
3445xmlXPathCastBooleanToString (int val) {
3446 xmlChar *ret;
3447 if (val)
3448 ret = xmlStrdup((const xmlChar *) "true");
3449 else
3450 ret = xmlStrdup((const xmlChar *) "false");
3451 return(ret);
3452}
3453
3454/**
3455 * xmlXPathCastNumberToString:
3456 * @val: a number
3457 *
3458 * Converts a number to its string value.
3459 *
3460 * Returns a newly allocated string.
3461 */
3462xmlChar *
3463xmlXPathCastNumberToString (double val) {
3464 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003465 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003466 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003467 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003468 break;
3469 case -1:
3470 ret = xmlStrdup((const xmlChar *) "-Infinity");
3471 break;
3472 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003473 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003474 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003475 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3476 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003477 } else {
3478 /* could be improved */
3479 char buf[100];
3480 xmlXPathFormatNumber(val, buf, 100);
3481 ret = xmlStrdup((const xmlChar *) buf);
3482 }
3483 }
3484 return(ret);
3485}
3486
3487/**
3488 * xmlXPathCastNodeToString:
3489 * @node: a node
3490 *
3491 * Converts a node to its string value.
3492 *
3493 * Returns a newly allocated string.
3494 */
3495xmlChar *
3496xmlXPathCastNodeToString (xmlNodePtr node) {
3497 return(xmlNodeGetContent(node));
3498}
3499
3500/**
3501 * xmlXPathCastNodeSetToString:
3502 * @ns: a node-set
3503 *
3504 * Converts a node-set to its string value.
3505 *
3506 * Returns a newly allocated string.
3507 */
3508xmlChar *
3509xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3510 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3511 return(xmlStrdup((const xmlChar *) ""));
3512
3513 xmlXPathNodeSetSort(ns);
3514 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3515}
3516
3517/**
3518 * xmlXPathCastToString:
3519 * @val: an XPath object
3520 *
3521 * Converts an existing object to its string() equivalent
3522 *
3523 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003524 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003525 * string object).
3526 */
3527xmlChar *
3528xmlXPathCastToString(xmlXPathObjectPtr val) {
3529 xmlChar *ret = NULL;
3530
3531 if (val == NULL)
3532 return(xmlStrdup((const xmlChar *) ""));
3533 switch (val->type) {
3534 case XPATH_UNDEFINED:
3535#ifdef DEBUG_EXPR
3536 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3537#endif
3538 ret = xmlStrdup((const xmlChar *) "");
3539 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003540 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003541 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003542 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3543 break;
3544 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003545 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003546 case XPATH_BOOLEAN:
3547 ret = xmlXPathCastBooleanToString(val->boolval);
3548 break;
3549 case XPATH_NUMBER: {
3550 ret = xmlXPathCastNumberToString(val->floatval);
3551 break;
3552 }
3553 case XPATH_USERS:
3554 case XPATH_POINT:
3555 case XPATH_RANGE:
3556 case XPATH_LOCATIONSET:
3557 TODO
3558 ret = xmlStrdup((const xmlChar *) "");
3559 break;
3560 }
3561 return(ret);
3562}
3563
3564/**
3565 * xmlXPathConvertString:
3566 * @val: an XPath object
3567 *
3568 * Converts an existing object to its string() equivalent
3569 *
3570 * Returns the new object, the old one is freed (or the operation
3571 * is done directly on @val)
3572 */
3573xmlXPathObjectPtr
3574xmlXPathConvertString(xmlXPathObjectPtr val) {
3575 xmlChar *res = NULL;
3576
3577 if (val == NULL)
3578 return(xmlXPathNewCString(""));
3579
3580 switch (val->type) {
3581 case XPATH_UNDEFINED:
3582#ifdef DEBUG_EXPR
3583 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3584#endif
3585 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003586 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003587 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003588 res = xmlXPathCastNodeSetToString(val->nodesetval);
3589 break;
3590 case XPATH_STRING:
3591 return(val);
3592 case XPATH_BOOLEAN:
3593 res = xmlXPathCastBooleanToString(val->boolval);
3594 break;
3595 case XPATH_NUMBER:
3596 res = xmlXPathCastNumberToString(val->floatval);
3597 break;
3598 case XPATH_USERS:
3599 case XPATH_POINT:
3600 case XPATH_RANGE:
3601 case XPATH_LOCATIONSET:
3602 TODO;
3603 break;
3604 }
3605 xmlXPathFreeObject(val);
3606 if (res == NULL)
3607 return(xmlXPathNewCString(""));
3608 return(xmlXPathWrapString(res));
3609}
3610
3611/**
3612 * xmlXPathCastBooleanToNumber:
3613 * @val: a boolean
3614 *
3615 * Converts a boolean to its number value
3616 *
3617 * Returns the number value
3618 */
3619double
3620xmlXPathCastBooleanToNumber(int val) {
3621 if (val)
3622 return(1.0);
3623 return(0.0);
3624}
3625
3626/**
3627 * xmlXPathCastStringToNumber:
3628 * @val: a string
3629 *
3630 * Converts a string to its number value
3631 *
3632 * Returns the number value
3633 */
3634double
3635xmlXPathCastStringToNumber(const xmlChar * val) {
3636 return(xmlXPathStringEvalNumber(val));
3637}
3638
3639/**
3640 * xmlXPathCastNodeToNumber:
3641 * @node: a node
3642 *
3643 * Converts a node to its number value
3644 *
3645 * Returns the number value
3646 */
3647double
3648xmlXPathCastNodeToNumber (xmlNodePtr node) {
3649 xmlChar *strval;
3650 double ret;
3651
3652 if (node == NULL)
3653 return(xmlXPathNAN);
3654 strval = xmlXPathCastNodeToString(node);
3655 if (strval == NULL)
3656 return(xmlXPathNAN);
3657 ret = xmlXPathCastStringToNumber(strval);
3658 xmlFree(strval);
3659
3660 return(ret);
3661}
3662
3663/**
3664 * xmlXPathCastNodeSetToNumber:
3665 * @ns: a node-set
3666 *
3667 * Converts a node-set to its number value
3668 *
3669 * Returns the number value
3670 */
3671double
3672xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3673 xmlChar *str;
3674 double ret;
3675
3676 if (ns == NULL)
3677 return(xmlXPathNAN);
3678 str = xmlXPathCastNodeSetToString(ns);
3679 ret = xmlXPathCastStringToNumber(str);
3680 xmlFree(str);
3681 return(ret);
3682}
3683
3684/**
3685 * xmlXPathCastToNumber:
3686 * @val: an XPath object
3687 *
3688 * Converts an XPath object to its number value
3689 *
3690 * Returns the number value
3691 */
3692double
3693xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3694 double ret = 0.0;
3695
3696 if (val == NULL)
3697 return(xmlXPathNAN);
3698 switch (val->type) {
3699 case XPATH_UNDEFINED:
3700#ifdef DEGUB_EXPR
3701 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3702#endif
3703 ret = xmlXPathNAN;
3704 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003705 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003706 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003707 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3708 break;
3709 case XPATH_STRING:
3710 ret = xmlXPathCastStringToNumber(val->stringval);
3711 break;
3712 case XPATH_NUMBER:
3713 ret = val->floatval;
3714 break;
3715 case XPATH_BOOLEAN:
3716 ret = xmlXPathCastBooleanToNumber(val->boolval);
3717 break;
3718 case XPATH_USERS:
3719 case XPATH_POINT:
3720 case XPATH_RANGE:
3721 case XPATH_LOCATIONSET:
3722 TODO;
3723 ret = xmlXPathNAN;
3724 break;
3725 }
3726 return(ret);
3727}
3728
3729/**
3730 * xmlXPathConvertNumber:
3731 * @val: an XPath object
3732 *
3733 * Converts an existing object to its number() equivalent
3734 *
3735 * Returns the new object, the old one is freed (or the operation
3736 * is done directly on @val)
3737 */
3738xmlXPathObjectPtr
3739xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3740 xmlXPathObjectPtr ret;
3741
3742 if (val == NULL)
3743 return(xmlXPathNewFloat(0.0));
3744 if (val->type == XPATH_NUMBER)
3745 return(val);
3746 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3747 xmlXPathFreeObject(val);
3748 return(ret);
3749}
3750
3751/**
3752 * xmlXPathCastNumberToBoolean:
3753 * @val: a number
3754 *
3755 * Converts a number to its boolean value
3756 *
3757 * Returns the boolean value
3758 */
3759int
3760xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003761 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003762 return(0);
3763 return(1);
3764}
3765
3766/**
3767 * xmlXPathCastStringToBoolean:
3768 * @val: a string
3769 *
3770 * Converts a string to its boolean value
3771 *
3772 * Returns the boolean value
3773 */
3774int
3775xmlXPathCastStringToBoolean (const xmlChar *val) {
3776 if ((val == NULL) || (xmlStrlen(val) == 0))
3777 return(0);
3778 return(1);
3779}
3780
3781/**
3782 * xmlXPathCastNodeSetToBoolean:
3783 * @ns: a node-set
3784 *
3785 * Converts a node-set to its boolean value
3786 *
3787 * Returns the boolean value
3788 */
3789int
3790xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3791 if ((ns == NULL) || (ns->nodeNr == 0))
3792 return(0);
3793 return(1);
3794}
3795
3796/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003797 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003798 * @val: an XPath object
3799 *
3800 * Converts an XPath object to its boolean value
3801 *
3802 * Returns the boolean value
3803 */
3804int
3805xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3806 int ret = 0;
3807
3808 if (val == NULL)
3809 return(0);
3810 switch (val->type) {
3811 case XPATH_UNDEFINED:
3812#ifdef DEBUG_EXPR
3813 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3814#endif
3815 ret = 0;
3816 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003817 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003818 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003819 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3820 break;
3821 case XPATH_STRING:
3822 ret = xmlXPathCastStringToBoolean(val->stringval);
3823 break;
3824 case XPATH_NUMBER:
3825 ret = xmlXPathCastNumberToBoolean(val->floatval);
3826 break;
3827 case XPATH_BOOLEAN:
3828 ret = val->boolval;
3829 break;
3830 case XPATH_USERS:
3831 case XPATH_POINT:
3832 case XPATH_RANGE:
3833 case XPATH_LOCATIONSET:
3834 TODO;
3835 ret = 0;
3836 break;
3837 }
3838 return(ret);
3839}
3840
3841
3842/**
3843 * xmlXPathConvertBoolean:
3844 * @val: an XPath object
3845 *
3846 * Converts an existing object to its boolean() equivalent
3847 *
3848 * Returns the new object, the old one is freed (or the operation
3849 * is done directly on @val)
3850 */
3851xmlXPathObjectPtr
3852xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3853 xmlXPathObjectPtr ret;
3854
3855 if (val == NULL)
3856 return(xmlXPathNewBoolean(0));
3857 if (val->type == XPATH_BOOLEAN)
3858 return(val);
3859 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3860 xmlXPathFreeObject(val);
3861 return(ret);
3862}
3863
Owen Taylor3473f882001-02-23 17:55:21 +00003864/************************************************************************
3865 * *
3866 * Routines to handle XPath contexts *
3867 * *
3868 ************************************************************************/
3869
3870/**
3871 * xmlXPathNewContext:
3872 * @doc: the XML document
3873 *
3874 * Create a new xmlXPathContext
3875 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003876 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003877 */
3878xmlXPathContextPtr
3879xmlXPathNewContext(xmlDocPtr doc) {
3880 xmlXPathContextPtr ret;
3881
3882 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3883 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003884 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003885 return(NULL);
3886 }
3887 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3888 ret->doc = doc;
3889 ret->node = NULL;
3890
3891 ret->varHash = NULL;
3892
3893 ret->nb_types = 0;
3894 ret->max_types = 0;
3895 ret->types = NULL;
3896
3897 ret->funcHash = xmlHashCreate(0);
3898
3899 ret->nb_axis = 0;
3900 ret->max_axis = 0;
3901 ret->axis = NULL;
3902
3903 ret->nsHash = NULL;
3904 ret->user = NULL;
3905
3906 ret->contextSize = -1;
3907 ret->proximityPosition = -1;
3908
3909 xmlXPathRegisterAllFunctions(ret);
3910
3911 return(ret);
3912}
3913
3914/**
3915 * xmlXPathFreeContext:
3916 * @ctxt: the context to free
3917 *
3918 * Free up an xmlXPathContext
3919 */
3920void
3921xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00003922 if (ctxt == NULL) return;
3923
Owen Taylor3473f882001-02-23 17:55:21 +00003924 xmlXPathRegisteredNsCleanup(ctxt);
3925 xmlXPathRegisteredFuncsCleanup(ctxt);
3926 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00003927 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00003928 xmlFree(ctxt);
3929}
3930
3931/************************************************************************
3932 * *
3933 * Routines to handle XPath parser contexts *
3934 * *
3935 ************************************************************************/
3936
3937#define CHECK_CTXT(ctxt) \
3938 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00003939 __xmlRaiseError(NULL, NULL, NULL, \
3940 NULL, NULL, XML_FROM_XPATH, \
3941 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
3942 __FILE__, __LINE__, \
3943 NULL, NULL, NULL, 0, 0, \
3944 "NULL context pointer\n"); \
3945 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00003946 } \
3947
3948
3949#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00003950 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
3951 (ctxt->doc->children == NULL)) { \
3952 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00003953 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00003954 }
Owen Taylor3473f882001-02-23 17:55:21 +00003955
3956
3957/**
3958 * xmlXPathNewParserContext:
3959 * @str: the XPath expression
3960 * @ctxt: the XPath context
3961 *
3962 * Create a new xmlXPathParserContext
3963 *
3964 * Returns the xmlXPathParserContext just allocated.
3965 */
3966xmlXPathParserContextPtr
3967xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3968 xmlXPathParserContextPtr ret;
3969
3970 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3971 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003972 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003973 return(NULL);
3974 }
3975 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3976 ret->cur = ret->base = str;
3977 ret->context = ctxt;
3978
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003979 ret->comp = xmlXPathNewCompExpr();
3980 if (ret->comp == NULL) {
3981 xmlFree(ret->valueTab);
3982 xmlFree(ret);
3983 return(NULL);
3984 }
Daniel Veillard4773df22004-01-23 13:15:13 +00003985 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
3986 ret->comp->dict = ctxt->dict;
3987 xmlDictReference(ret->comp->dict);
3988 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003989
3990 return(ret);
3991}
3992
3993/**
3994 * xmlXPathCompParserContext:
3995 * @comp: the XPath compiled expression
3996 * @ctxt: the XPath context
3997 *
3998 * Create a new xmlXPathParserContext when processing a compiled expression
3999 *
4000 * Returns the xmlXPathParserContext just allocated.
4001 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004002static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004003xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4004 xmlXPathParserContextPtr ret;
4005
4006 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4007 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004008 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004009 return(NULL);
4010 }
4011 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4012
Owen Taylor3473f882001-02-23 17:55:21 +00004013 /* Allocate the value stack */
4014 ret->valueTab = (xmlXPathObjectPtr *)
4015 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004016 if (ret->valueTab == NULL) {
4017 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004018 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004019 return(NULL);
4020 }
Owen Taylor3473f882001-02-23 17:55:21 +00004021 ret->valueNr = 0;
4022 ret->valueMax = 10;
4023 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004024
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004025 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004026 ret->comp = comp;
4027
Owen Taylor3473f882001-02-23 17:55:21 +00004028 return(ret);
4029}
4030
4031/**
4032 * xmlXPathFreeParserContext:
4033 * @ctxt: the context to free
4034 *
4035 * Free up an xmlXPathParserContext
4036 */
4037void
4038xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
4039 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004040 xmlFree(ctxt->valueTab);
4041 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004042 if (ctxt->comp)
4043 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00004044 xmlFree(ctxt);
4045}
4046
4047/************************************************************************
4048 * *
4049 * The implicit core function library *
4050 * *
4051 ************************************************************************/
4052
Owen Taylor3473f882001-02-23 17:55:21 +00004053/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004054 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00004055 * @node: a node pointer
4056 *
4057 * Function computing the beginning of the string value of the node,
4058 * used to speed up comparisons
4059 *
4060 * Returns an int usable as a hash
4061 */
4062static unsigned int
4063xmlXPathNodeValHash(xmlNodePtr node) {
4064 int len = 2;
4065 const xmlChar * string = NULL;
4066 xmlNodePtr tmp = NULL;
4067 unsigned int ret = 0;
4068
4069 if (node == NULL)
4070 return(0);
4071
Daniel Veillard9adc0462003-03-24 18:39:54 +00004072 if (node->type == XML_DOCUMENT_NODE) {
4073 tmp = xmlDocGetRootElement((xmlDocPtr) node);
4074 if (tmp == NULL)
4075 node = node->children;
4076 else
4077 node = tmp;
4078
4079 if (node == NULL)
4080 return(0);
4081 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004082
4083 switch (node->type) {
4084 case XML_COMMENT_NODE:
4085 case XML_PI_NODE:
4086 case XML_CDATA_SECTION_NODE:
4087 case XML_TEXT_NODE:
4088 string = node->content;
4089 if (string == NULL)
4090 return(0);
4091 if (string[0] == 0)
4092 return(0);
4093 return(((unsigned int) string[0]) +
4094 (((unsigned int) string[1]) << 8));
4095 case XML_NAMESPACE_DECL:
4096 string = ((xmlNsPtr)node)->href;
4097 if (string == NULL)
4098 return(0);
4099 if (string[0] == 0)
4100 return(0);
4101 return(((unsigned int) string[0]) +
4102 (((unsigned int) string[1]) << 8));
4103 case XML_ATTRIBUTE_NODE:
4104 tmp = ((xmlAttrPtr) node)->children;
4105 break;
4106 case XML_ELEMENT_NODE:
4107 tmp = node->children;
4108 break;
4109 default:
4110 return(0);
4111 }
4112 while (tmp != NULL) {
4113 switch (tmp->type) {
4114 case XML_COMMENT_NODE:
4115 case XML_PI_NODE:
4116 case XML_CDATA_SECTION_NODE:
4117 case XML_TEXT_NODE:
4118 string = tmp->content;
4119 break;
4120 case XML_NAMESPACE_DECL:
4121 string = ((xmlNsPtr)tmp)->href;
4122 break;
4123 default:
4124 break;
4125 }
4126 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004127 if (len == 1) {
4128 return(ret + (((unsigned int) string[0]) << 8));
4129 }
4130 if (string[1] == 0) {
4131 len = 1;
4132 ret = (unsigned int) string[0];
4133 } else {
4134 return(((unsigned int) string[0]) +
4135 (((unsigned int) string[1]) << 8));
4136 }
4137 }
4138 /*
4139 * Skip to next node
4140 */
4141 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4142 if (tmp->children->type != XML_ENTITY_DECL) {
4143 tmp = tmp->children;
4144 continue;
4145 }
4146 }
4147 if (tmp == node)
4148 break;
4149
4150 if (tmp->next != NULL) {
4151 tmp = tmp->next;
4152 continue;
4153 }
4154
4155 do {
4156 tmp = tmp->parent;
4157 if (tmp == NULL)
4158 break;
4159 if (tmp == node) {
4160 tmp = NULL;
4161 break;
4162 }
4163 if (tmp->next != NULL) {
4164 tmp = tmp->next;
4165 break;
4166 }
4167 } while (tmp != NULL);
4168 }
4169 return(ret);
4170}
4171
4172/**
4173 * xmlXPathStringHash:
4174 * @string: a string
4175 *
4176 * Function computing the beginning of the string value of the node,
4177 * used to speed up comparisons
4178 *
4179 * Returns an int usable as a hash
4180 */
4181static unsigned int
4182xmlXPathStringHash(const xmlChar * string) {
4183 if (string == NULL)
4184 return((unsigned int) 0);
4185 if (string[0] == 0)
4186 return(0);
4187 return(((unsigned int) string[0]) +
4188 (((unsigned int) string[1]) << 8));
4189}
4190
4191/**
Owen Taylor3473f882001-02-23 17:55:21 +00004192 * xmlXPathCompareNodeSetFloat:
4193 * @ctxt: the XPath Parser context
4194 * @inf: less than (1) or greater than (0)
4195 * @strict: is the comparison strict
4196 * @arg: the node set
4197 * @f: the value
4198 *
4199 * Implement the compare operation between a nodeset and a number
4200 * @ns < @val (1, 1, ...
4201 * @ns <= @val (1, 0, ...
4202 * @ns > @val (0, 1, ...
4203 * @ns >= @val (0, 0, ...
4204 *
4205 * If one object to be compared is a node-set and the other is a number,
4206 * then the comparison will be true if and only if there is a node in the
4207 * node-set such that the result of performing the comparison on the number
4208 * to be compared and on the result of converting the string-value of that
4209 * node to a number using the number function is true.
4210 *
4211 * Returns 0 or 1 depending on the results of the test.
4212 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004213static int
Owen Taylor3473f882001-02-23 17:55:21 +00004214xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4215 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4216 int i, ret = 0;
4217 xmlNodeSetPtr ns;
4218 xmlChar *str2;
4219
4220 if ((f == NULL) || (arg == NULL) ||
4221 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4222 xmlXPathFreeObject(arg);
4223 xmlXPathFreeObject(f);
4224 return(0);
4225 }
4226 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004227 if (ns != NULL) {
4228 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004229 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004230 if (str2 != NULL) {
4231 valuePush(ctxt,
4232 xmlXPathNewString(str2));
4233 xmlFree(str2);
4234 xmlXPathNumberFunction(ctxt, 1);
4235 valuePush(ctxt, xmlXPathObjectCopy(f));
4236 ret = xmlXPathCompareValues(ctxt, inf, strict);
4237 if (ret)
4238 break;
4239 }
4240 }
Owen Taylor3473f882001-02-23 17:55:21 +00004241 }
4242 xmlXPathFreeObject(arg);
4243 xmlXPathFreeObject(f);
4244 return(ret);
4245}
4246
4247/**
4248 * xmlXPathCompareNodeSetString:
4249 * @ctxt: the XPath Parser context
4250 * @inf: less than (1) or greater than (0)
4251 * @strict: is the comparison strict
4252 * @arg: the node set
4253 * @s: the value
4254 *
4255 * Implement the compare operation between a nodeset and a string
4256 * @ns < @val (1, 1, ...
4257 * @ns <= @val (1, 0, ...
4258 * @ns > @val (0, 1, ...
4259 * @ns >= @val (0, 0, ...
4260 *
4261 * If one object to be compared is a node-set and the other is a string,
4262 * then the comparison will be true if and only if there is a node in
4263 * the node-set such that the result of performing the comparison on the
4264 * string-value of the node and the other string is true.
4265 *
4266 * Returns 0 or 1 depending on the results of the test.
4267 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004268static int
Owen Taylor3473f882001-02-23 17:55:21 +00004269xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4270 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4271 int i, ret = 0;
4272 xmlNodeSetPtr ns;
4273 xmlChar *str2;
4274
4275 if ((s == NULL) || (arg == NULL) ||
4276 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4277 xmlXPathFreeObject(arg);
4278 xmlXPathFreeObject(s);
4279 return(0);
4280 }
4281 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004282 if (ns != NULL) {
4283 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004284 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004285 if (str2 != NULL) {
4286 valuePush(ctxt,
4287 xmlXPathNewString(str2));
4288 xmlFree(str2);
4289 valuePush(ctxt, xmlXPathObjectCopy(s));
4290 ret = xmlXPathCompareValues(ctxt, inf, strict);
4291 if (ret)
4292 break;
4293 }
4294 }
Owen Taylor3473f882001-02-23 17:55:21 +00004295 }
4296 xmlXPathFreeObject(arg);
4297 xmlXPathFreeObject(s);
4298 return(ret);
4299}
4300
4301/**
4302 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004303 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004304 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004305 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004306 * @arg2: the second node set object
4307 *
4308 * Implement the compare operation on nodesets:
4309 *
4310 * If both objects to be compared are node-sets, then the comparison
4311 * will be true if and only if there is a node in the first node-set
4312 * and a node in the second node-set such that the result of performing
4313 * the comparison on the string-values of the two nodes is true.
4314 * ....
4315 * When neither object to be compared is a node-set and the operator
4316 * is <=, <, >= or >, then the objects are compared by converting both
4317 * objects to numbers and comparing the numbers according to IEEE 754.
4318 * ....
4319 * The number function converts its argument to a number as follows:
4320 * - a string that consists of optional whitespace followed by an
4321 * optional minus sign followed by a Number followed by whitespace
4322 * is converted to the IEEE 754 number that is nearest (according
4323 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4324 * represented by the string; any other string is converted to NaN
4325 *
4326 * Conclusion all nodes need to be converted first to their string value
4327 * and then the comparison must be done when possible
4328 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004329static int
4330xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004331 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4332 int i, j, init = 0;
4333 double val1;
4334 double *values2;
4335 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004336 xmlNodeSetPtr ns1;
4337 xmlNodeSetPtr ns2;
4338
4339 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004340 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4341 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004342 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004343 }
Owen Taylor3473f882001-02-23 17:55:21 +00004344 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004345 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4346 xmlXPathFreeObject(arg1);
4347 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004348 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004349 }
Owen Taylor3473f882001-02-23 17:55:21 +00004350
4351 ns1 = arg1->nodesetval;
4352 ns2 = arg2->nodesetval;
4353
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004354 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004355 xmlXPathFreeObject(arg1);
4356 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004357 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004358 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004359 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004360 xmlXPathFreeObject(arg1);
4361 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004362 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004363 }
Owen Taylor3473f882001-02-23 17:55:21 +00004364
4365 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4366 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004367 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004368 xmlXPathFreeObject(arg1);
4369 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004370 return(0);
4371 }
4372 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004373 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004374 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004375 continue;
4376 for (j = 0;j < ns2->nodeNr;j++) {
4377 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004378 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004379 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004380 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004381 continue;
4382 if (inf && strict)
4383 ret = (val1 < values2[j]);
4384 else if (inf && !strict)
4385 ret = (val1 <= values2[j]);
4386 else if (!inf && strict)
4387 ret = (val1 > values2[j]);
4388 else if (!inf && !strict)
4389 ret = (val1 >= values2[j]);
4390 if (ret)
4391 break;
4392 }
4393 if (ret)
4394 break;
4395 init = 1;
4396 }
4397 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004398 xmlXPathFreeObject(arg1);
4399 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004400 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004401}
4402
4403/**
4404 * xmlXPathCompareNodeSetValue:
4405 * @ctxt: the XPath Parser context
4406 * @inf: less than (1) or greater than (0)
4407 * @strict: is the comparison strict
4408 * @arg: the node set
4409 * @val: the value
4410 *
4411 * Implement the compare operation between a nodeset and a value
4412 * @ns < @val (1, 1, ...
4413 * @ns <= @val (1, 0, ...
4414 * @ns > @val (0, 1, ...
4415 * @ns >= @val (0, 0, ...
4416 *
4417 * If one object to be compared is a node-set and the other is a boolean,
4418 * then the comparison will be true if and only if the result of performing
4419 * the comparison on the boolean and on the result of converting
4420 * the node-set to a boolean using the boolean function is true.
4421 *
4422 * Returns 0 or 1 depending on the results of the test.
4423 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004424static int
Owen Taylor3473f882001-02-23 17:55:21 +00004425xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4426 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4427 if ((val == NULL) || (arg == NULL) ||
4428 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4429 return(0);
4430
4431 switch(val->type) {
4432 case XPATH_NUMBER:
4433 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4434 case XPATH_NODESET:
4435 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004436 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004437 case XPATH_STRING:
4438 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4439 case XPATH_BOOLEAN:
4440 valuePush(ctxt, arg);
4441 xmlXPathBooleanFunction(ctxt, 1);
4442 valuePush(ctxt, val);
4443 return(xmlXPathCompareValues(ctxt, inf, strict));
4444 default:
4445 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004446 }
4447 return(0);
4448}
4449
4450/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004451 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004452 * @arg: the nodeset object argument
4453 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004454 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004455 *
4456 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4457 * If one object to be compared is a node-set and the other is a string,
4458 * then the comparison will be true if and only if there is a node in
4459 * the node-set such that the result of performing the comparison on the
4460 * string-value of the node and the other string is true.
4461 *
4462 * Returns 0 or 1 depending on the results of the test.
4463 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004464static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004465xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004466{
Owen Taylor3473f882001-02-23 17:55:21 +00004467 int i;
4468 xmlNodeSetPtr ns;
4469 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004470 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004471
4472 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004473 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4474 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004475 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004476 /*
4477 * A NULL nodeset compared with a string is always false
4478 * (since there is no node equal, and no node not equal)
4479 */
4480 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004481 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004482 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004483 for (i = 0; i < ns->nodeNr; i++) {
4484 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4485 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4486 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4487 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004488 if (neq)
4489 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004490 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004491 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4492 if (neq)
4493 continue;
4494 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004495 } else if (neq) {
4496 if (str2 != NULL)
4497 xmlFree(str2);
4498 return (1);
4499 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004500 if (str2 != NULL)
4501 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004502 } else if (neq)
4503 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004504 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004505 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004506}
4507
4508/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004509 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004510 * @arg: the nodeset object argument
4511 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004512 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004513 *
4514 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4515 * If one object to be compared is a node-set and the other is a number,
4516 * then the comparison will be true if and only if there is a node in
4517 * the node-set such that the result of performing the comparison on the
4518 * number to be compared and on the result of converting the string-value
4519 * of that node to a number using the number function is true.
4520 *
4521 * Returns 0 or 1 depending on the results of the test.
4522 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004523static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004524xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4525 xmlXPathObjectPtr arg, double f, int neq) {
4526 int i, ret=0;
4527 xmlNodeSetPtr ns;
4528 xmlChar *str2;
4529 xmlXPathObjectPtr val;
4530 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004531
4532 if ((arg == NULL) ||
4533 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4534 return(0);
4535
William M. Brack0c022ad2002-07-12 00:56:01 +00004536 ns = arg->nodesetval;
4537 if (ns != NULL) {
4538 for (i=0;i<ns->nodeNr;i++) {
4539 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4540 if (str2 != NULL) {
4541 valuePush(ctxt, xmlXPathNewString(str2));
4542 xmlFree(str2);
4543 xmlXPathNumberFunction(ctxt, 1);
4544 val = valuePop(ctxt);
4545 v = val->floatval;
4546 xmlXPathFreeObject(val);
4547 if (!xmlXPathIsNaN(v)) {
4548 if ((!neq) && (v==f)) {
4549 ret = 1;
4550 break;
4551 } else if ((neq) && (v!=f)) {
4552 ret = 1;
4553 break;
4554 }
4555 }
4556 }
4557 }
4558 }
4559
4560 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004561}
4562
4563
4564/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004565 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004566 * @arg1: first nodeset object argument
4567 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004568 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004569 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004570 * Implement the equal / not equal operation on XPath nodesets:
4571 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004572 * If both objects to be compared are node-sets, then the comparison
4573 * will be true if and only if there is a node in the first node-set and
4574 * a node in the second node-set such that the result of performing the
4575 * comparison on the string-values of the two nodes is true.
4576 *
4577 * (needless to say, this is a costly operation)
4578 *
4579 * Returns 0 or 1 depending on the results of the test.
4580 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004581static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004582xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004583 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004584 unsigned int *hashs1;
4585 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004586 xmlChar **values1;
4587 xmlChar **values2;
4588 int ret = 0;
4589 xmlNodeSetPtr ns1;
4590 xmlNodeSetPtr ns2;
4591
4592 if ((arg1 == NULL) ||
4593 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4594 return(0);
4595 if ((arg2 == NULL) ||
4596 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4597 return(0);
4598
4599 ns1 = arg1->nodesetval;
4600 ns2 = arg2->nodesetval;
4601
Daniel Veillard911f49a2001-04-07 15:39:35 +00004602 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004603 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004604 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004605 return(0);
4606
4607 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004608 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004609 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004610 if (neq == 0)
4611 for (i = 0;i < ns1->nodeNr;i++)
4612 for (j = 0;j < ns2->nodeNr;j++)
4613 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4614 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004615
4616 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004617 if (values1 == NULL) {
4618 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004619 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004620 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004621 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4622 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004623 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004624 xmlFree(values1);
4625 return(0);
4626 }
Owen Taylor3473f882001-02-23 17:55:21 +00004627 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4628 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4629 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004630 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004631 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004632 xmlFree(values1);
4633 return(0);
4634 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004635 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4636 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004637 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004638 xmlFree(hashs1);
4639 xmlFree(values1);
4640 xmlFree(values2);
4641 return(0);
4642 }
Owen Taylor3473f882001-02-23 17:55:21 +00004643 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4644 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004645 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004646 for (j = 0;j < ns2->nodeNr;j++) {
4647 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004648 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004649 if (hashs1[i] != hashs2[j]) {
4650 if (neq) {
4651 ret = 1;
4652 break;
4653 }
4654 }
4655 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004656 if (values1[i] == NULL)
4657 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4658 if (values2[j] == NULL)
4659 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004660 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004661 if (ret)
4662 break;
4663 }
Owen Taylor3473f882001-02-23 17:55:21 +00004664 }
4665 if (ret)
4666 break;
4667 }
4668 for (i = 0;i < ns1->nodeNr;i++)
4669 if (values1[i] != NULL)
4670 xmlFree(values1[i]);
4671 for (j = 0;j < ns2->nodeNr;j++)
4672 if (values2[j] != NULL)
4673 xmlFree(values2[j]);
4674 xmlFree(values1);
4675 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004676 xmlFree(hashs1);
4677 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004678 return(ret);
4679}
4680
William M. Brack0c022ad2002-07-12 00:56:01 +00004681static int
4682xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4683 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004684 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004685 /*
4686 *At this point we are assured neither arg1 nor arg2
4687 *is a nodeset, so we can just pick the appropriate routine.
4688 */
Owen Taylor3473f882001-02-23 17:55:21 +00004689 switch (arg1->type) {
4690 case XPATH_UNDEFINED:
4691#ifdef DEBUG_EXPR
4692 xmlGenericError(xmlGenericErrorContext,
4693 "Equal: undefined\n");
4694#endif
4695 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004696 case XPATH_BOOLEAN:
4697 switch (arg2->type) {
4698 case XPATH_UNDEFINED:
4699#ifdef DEBUG_EXPR
4700 xmlGenericError(xmlGenericErrorContext,
4701 "Equal: undefined\n");
4702#endif
4703 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004704 case XPATH_BOOLEAN:
4705#ifdef DEBUG_EXPR
4706 xmlGenericError(xmlGenericErrorContext,
4707 "Equal: %d boolean %d \n",
4708 arg1->boolval, arg2->boolval);
4709#endif
4710 ret = (arg1->boolval == arg2->boolval);
4711 break;
4712 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004713 ret = (arg1->boolval ==
4714 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004715 break;
4716 case XPATH_STRING:
4717 if ((arg2->stringval == NULL) ||
4718 (arg2->stringval[0] == 0)) ret = 0;
4719 else
4720 ret = 1;
4721 ret = (arg1->boolval == ret);
4722 break;
4723 case XPATH_USERS:
4724 case XPATH_POINT:
4725 case XPATH_RANGE:
4726 case XPATH_LOCATIONSET:
4727 TODO
4728 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004729 case XPATH_NODESET:
4730 case XPATH_XSLT_TREE:
4731 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004732 }
4733 break;
4734 case XPATH_NUMBER:
4735 switch (arg2->type) {
4736 case XPATH_UNDEFINED:
4737#ifdef DEBUG_EXPR
4738 xmlGenericError(xmlGenericErrorContext,
4739 "Equal: undefined\n");
4740#endif
4741 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004742 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004743 ret = (arg2->boolval==
4744 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004745 break;
4746 case XPATH_STRING:
4747 valuePush(ctxt, arg2);
4748 xmlXPathNumberFunction(ctxt, 1);
4749 arg2 = valuePop(ctxt);
4750 /* no break on purpose */
4751 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004752 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004753 if (xmlXPathIsNaN(arg1->floatval) ||
4754 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004755 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004756 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4757 if (xmlXPathIsInf(arg2->floatval) == 1)
4758 ret = 1;
4759 else
4760 ret = 0;
4761 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4762 if (xmlXPathIsInf(arg2->floatval) == -1)
4763 ret = 1;
4764 else
4765 ret = 0;
4766 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4767 if (xmlXPathIsInf(arg1->floatval) == 1)
4768 ret = 1;
4769 else
4770 ret = 0;
4771 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4772 if (xmlXPathIsInf(arg1->floatval) == -1)
4773 ret = 1;
4774 else
4775 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004776 } else {
4777 ret = (arg1->floatval == arg2->floatval);
4778 }
Owen Taylor3473f882001-02-23 17:55:21 +00004779 break;
4780 case XPATH_USERS:
4781 case XPATH_POINT:
4782 case XPATH_RANGE:
4783 case XPATH_LOCATIONSET:
4784 TODO
4785 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004786 case XPATH_NODESET:
4787 case XPATH_XSLT_TREE:
4788 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004789 }
4790 break;
4791 case XPATH_STRING:
4792 switch (arg2->type) {
4793 case XPATH_UNDEFINED:
4794#ifdef DEBUG_EXPR
4795 xmlGenericError(xmlGenericErrorContext,
4796 "Equal: undefined\n");
4797#endif
4798 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004799 case XPATH_BOOLEAN:
4800 if ((arg1->stringval == NULL) ||
4801 (arg1->stringval[0] == 0)) ret = 0;
4802 else
4803 ret = 1;
4804 ret = (arg2->boolval == ret);
4805 break;
4806 case XPATH_STRING:
4807 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4808 break;
4809 case XPATH_NUMBER:
4810 valuePush(ctxt, arg1);
4811 xmlXPathNumberFunction(ctxt, 1);
4812 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004813 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004814 if (xmlXPathIsNaN(arg1->floatval) ||
4815 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004816 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004817 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4818 if (xmlXPathIsInf(arg2->floatval) == 1)
4819 ret = 1;
4820 else
4821 ret = 0;
4822 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4823 if (xmlXPathIsInf(arg2->floatval) == -1)
4824 ret = 1;
4825 else
4826 ret = 0;
4827 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4828 if (xmlXPathIsInf(arg1->floatval) == 1)
4829 ret = 1;
4830 else
4831 ret = 0;
4832 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4833 if (xmlXPathIsInf(arg1->floatval) == -1)
4834 ret = 1;
4835 else
4836 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004837 } else {
4838 ret = (arg1->floatval == arg2->floatval);
4839 }
Owen Taylor3473f882001-02-23 17:55:21 +00004840 break;
4841 case XPATH_USERS:
4842 case XPATH_POINT:
4843 case XPATH_RANGE:
4844 case XPATH_LOCATIONSET:
4845 TODO
4846 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004847 case XPATH_NODESET:
4848 case XPATH_XSLT_TREE:
4849 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004850 }
4851 break;
4852 case XPATH_USERS:
4853 case XPATH_POINT:
4854 case XPATH_RANGE:
4855 case XPATH_LOCATIONSET:
4856 TODO
4857 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004858 case XPATH_NODESET:
4859 case XPATH_XSLT_TREE:
4860 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004861 }
4862 xmlXPathFreeObject(arg1);
4863 xmlXPathFreeObject(arg2);
4864 return(ret);
4865}
4866
William M. Brack0c022ad2002-07-12 00:56:01 +00004867/**
4868 * xmlXPathEqualValues:
4869 * @ctxt: the XPath Parser context
4870 *
4871 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4872 *
4873 * Returns 0 or 1 depending on the results of the test.
4874 */
4875int
4876xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4877 xmlXPathObjectPtr arg1, arg2, argtmp;
4878 int ret = 0;
4879
Daniel Veillard6128c012004-11-08 17:16:15 +00004880 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00004881 arg2 = valuePop(ctxt);
4882 arg1 = valuePop(ctxt);
4883 if ((arg1 == NULL) || (arg2 == NULL)) {
4884 if (arg1 != NULL)
4885 xmlXPathFreeObject(arg1);
4886 else
4887 xmlXPathFreeObject(arg2);
4888 XP_ERROR0(XPATH_INVALID_OPERAND);
4889 }
4890
4891 if (arg1 == arg2) {
4892#ifdef DEBUG_EXPR
4893 xmlGenericError(xmlGenericErrorContext,
4894 "Equal: by pointer\n");
4895#endif
4896 return(1);
4897 }
4898
4899 /*
4900 *If either argument is a nodeset, it's a 'special case'
4901 */
4902 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4903 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4904 /*
4905 *Hack it to assure arg1 is the nodeset
4906 */
4907 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4908 argtmp = arg2;
4909 arg2 = arg1;
4910 arg1 = argtmp;
4911 }
4912 switch (arg2->type) {
4913 case XPATH_UNDEFINED:
4914#ifdef DEBUG_EXPR
4915 xmlGenericError(xmlGenericErrorContext,
4916 "Equal: undefined\n");
4917#endif
4918 break;
4919 case XPATH_NODESET:
4920 case XPATH_XSLT_TREE:
4921 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4922 break;
4923 case XPATH_BOOLEAN:
4924 if ((arg1->nodesetval == NULL) ||
4925 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4926 else
4927 ret = 1;
4928 ret = (ret == arg2->boolval);
4929 break;
4930 case XPATH_NUMBER:
4931 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4932 break;
4933 case XPATH_STRING:
4934 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4935 break;
4936 case XPATH_USERS:
4937 case XPATH_POINT:
4938 case XPATH_RANGE:
4939 case XPATH_LOCATIONSET:
4940 TODO
4941 break;
4942 }
4943 xmlXPathFreeObject(arg1);
4944 xmlXPathFreeObject(arg2);
4945 return(ret);
4946 }
4947
4948 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4949}
4950
4951/**
4952 * xmlXPathNotEqualValues:
4953 * @ctxt: the XPath Parser context
4954 *
4955 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4956 *
4957 * Returns 0 or 1 depending on the results of the test.
4958 */
4959int
4960xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4961 xmlXPathObjectPtr arg1, arg2, argtmp;
4962 int ret = 0;
4963
Daniel Veillard6128c012004-11-08 17:16:15 +00004964 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00004965 arg2 = valuePop(ctxt);
4966 arg1 = valuePop(ctxt);
4967 if ((arg1 == NULL) || (arg2 == NULL)) {
4968 if (arg1 != NULL)
4969 xmlXPathFreeObject(arg1);
4970 else
4971 xmlXPathFreeObject(arg2);
4972 XP_ERROR0(XPATH_INVALID_OPERAND);
4973 }
4974
4975 if (arg1 == arg2) {
4976#ifdef DEBUG_EXPR
4977 xmlGenericError(xmlGenericErrorContext,
4978 "NotEqual: by pointer\n");
4979#endif
4980 return(0);
4981 }
4982
4983 /*
4984 *If either argument is a nodeset, it's a 'special case'
4985 */
4986 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4987 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4988 /*
4989 *Hack it to assure arg1 is the nodeset
4990 */
4991 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4992 argtmp = arg2;
4993 arg2 = arg1;
4994 arg1 = argtmp;
4995 }
4996 switch (arg2->type) {
4997 case XPATH_UNDEFINED:
4998#ifdef DEBUG_EXPR
4999 xmlGenericError(xmlGenericErrorContext,
5000 "NotEqual: undefined\n");
5001#endif
5002 break;
5003 case XPATH_NODESET:
5004 case XPATH_XSLT_TREE:
5005 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
5006 break;
5007 case XPATH_BOOLEAN:
5008 if ((arg1->nodesetval == NULL) ||
5009 (arg1->nodesetval->nodeNr == 0)) ret = 0;
5010 else
5011 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00005012 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00005013 break;
5014 case XPATH_NUMBER:
5015 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5016 break;
5017 case XPATH_STRING:
5018 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
5019 break;
5020 case XPATH_USERS:
5021 case XPATH_POINT:
5022 case XPATH_RANGE:
5023 case XPATH_LOCATIONSET:
5024 TODO
5025 break;
5026 }
5027 xmlXPathFreeObject(arg1);
5028 xmlXPathFreeObject(arg2);
5029 return(ret);
5030 }
5031
5032 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5033}
Owen Taylor3473f882001-02-23 17:55:21 +00005034
5035/**
5036 * xmlXPathCompareValues:
5037 * @ctxt: the XPath Parser context
5038 * @inf: less than (1) or greater than (0)
5039 * @strict: is the comparison strict
5040 *
5041 * Implement the compare operation on XPath objects:
5042 * @arg1 < @arg2 (1, 1, ...
5043 * @arg1 <= @arg2 (1, 0, ...
5044 * @arg1 > @arg2 (0, 1, ...
5045 * @arg1 >= @arg2 (0, 0, ...
5046 *
5047 * When neither object to be compared is a node-set and the operator is
5048 * <=, <, >=, >, then the objects are compared by converted both objects
5049 * to numbers and comparing the numbers according to IEEE 754. The <
5050 * comparison will be true if and only if the first number is less than the
5051 * second number. The <= comparison will be true if and only if the first
5052 * number is less than or equal to the second number. The > comparison
5053 * will be true if and only if the first number is greater than the second
5054 * number. The >= comparison will be true if and only if the first number
5055 * is greater than or equal to the second number.
5056 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005057 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005058 */
5059int
5060xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005061 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005062 xmlXPathObjectPtr arg1, arg2;
5063
Daniel Veillard6128c012004-11-08 17:16:15 +00005064 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005065 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005066 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005067 if ((arg1 == NULL) || (arg2 == NULL)) {
5068 if (arg1 != NULL)
5069 xmlXPathFreeObject(arg1);
5070 else
5071 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005072 XP_ERROR0(XPATH_INVALID_OPERAND);
5073 }
5074
William M. Brack0c022ad2002-07-12 00:56:01 +00005075 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5076 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5077 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5078 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005079 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005080 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005081 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005082 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5083 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005084 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005085 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5086 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005087 }
5088 }
5089 return(ret);
5090 }
5091
5092 if (arg1->type != XPATH_NUMBER) {
5093 valuePush(ctxt, arg1);
5094 xmlXPathNumberFunction(ctxt, 1);
5095 arg1 = valuePop(ctxt);
5096 }
5097 if (arg1->type != XPATH_NUMBER) {
5098 xmlXPathFreeObject(arg1);
5099 xmlXPathFreeObject(arg2);
5100 XP_ERROR0(XPATH_INVALID_OPERAND);
5101 }
5102 if (arg2->type != XPATH_NUMBER) {
5103 valuePush(ctxt, arg2);
5104 xmlXPathNumberFunction(ctxt, 1);
5105 arg2 = valuePop(ctxt);
5106 }
5107 if (arg2->type != XPATH_NUMBER) {
5108 xmlXPathFreeObject(arg1);
5109 xmlXPathFreeObject(arg2);
5110 XP_ERROR0(XPATH_INVALID_OPERAND);
5111 }
5112 /*
5113 * Add tests for infinity and nan
5114 * => feedback on 3.4 for Inf and NaN
5115 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005116 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005117 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005118 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005119 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005120 arg1i=xmlXPathIsInf(arg1->floatval);
5121 arg2i=xmlXPathIsInf(arg2->floatval);
5122 if (inf && strict) {
5123 if ((arg1i == -1 && arg2i != -1) ||
5124 (arg2i == 1 && arg1i != 1)) {
5125 ret = 1;
5126 } else if (arg1i == 0 && arg2i == 0) {
5127 ret = (arg1->floatval < arg2->floatval);
5128 } else {
5129 ret = 0;
5130 }
5131 }
5132 else if (inf && !strict) {
5133 if (arg1i == -1 || arg2i == 1) {
5134 ret = 1;
5135 } else if (arg1i == 0 && arg2i == 0) {
5136 ret = (arg1->floatval <= arg2->floatval);
5137 } else {
5138 ret = 0;
5139 }
5140 }
5141 else if (!inf && strict) {
5142 if ((arg1i == 1 && arg2i != 1) ||
5143 (arg2i == -1 && arg1i != -1)) {
5144 ret = 1;
5145 } else if (arg1i == 0 && arg2i == 0) {
5146 ret = (arg1->floatval > arg2->floatval);
5147 } else {
5148 ret = 0;
5149 }
5150 }
5151 else if (!inf && !strict) {
5152 if (arg1i == 1 || arg2i == -1) {
5153 ret = 1;
5154 } else if (arg1i == 0 && arg2i == 0) {
5155 ret = (arg1->floatval >= arg2->floatval);
5156 } else {
5157 ret = 0;
5158 }
5159 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005160 }
Owen Taylor3473f882001-02-23 17:55:21 +00005161 xmlXPathFreeObject(arg1);
5162 xmlXPathFreeObject(arg2);
5163 return(ret);
5164}
5165
5166/**
5167 * xmlXPathValueFlipSign:
5168 * @ctxt: the XPath Parser context
5169 *
5170 * Implement the unary - operation on an XPath object
5171 * The numeric operators convert their operands to numbers as if
5172 * by calling the number function.
5173 */
5174void
5175xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005176 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005177 CAST_TO_NUMBER;
5178 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005179 if (xmlXPathIsNaN(ctxt->value->floatval))
5180 ctxt->value->floatval=xmlXPathNAN;
5181 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5182 ctxt->value->floatval=xmlXPathNINF;
5183 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5184 ctxt->value->floatval=xmlXPathPINF;
5185 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005186 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5187 ctxt->value->floatval = xmlXPathNZERO;
5188 else
5189 ctxt->value->floatval = 0;
5190 }
5191 else
5192 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005193}
5194
5195/**
5196 * xmlXPathAddValues:
5197 * @ctxt: the XPath Parser context
5198 *
5199 * Implement the add operation on XPath objects:
5200 * The numeric operators convert their operands to numbers as if
5201 * by calling the number function.
5202 */
5203void
5204xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5205 xmlXPathObjectPtr arg;
5206 double val;
5207
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005208 arg = valuePop(ctxt);
5209 if (arg == NULL)
5210 XP_ERROR(XPATH_INVALID_OPERAND);
5211 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005212 xmlXPathFreeObject(arg);
5213
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005214 CAST_TO_NUMBER;
5215 CHECK_TYPE(XPATH_NUMBER);
5216 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005217}
5218
5219/**
5220 * xmlXPathSubValues:
5221 * @ctxt: the XPath Parser context
5222 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005223 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005224 * The numeric operators convert their operands to numbers as if
5225 * by calling the number function.
5226 */
5227void
5228xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5229 xmlXPathObjectPtr arg;
5230 double val;
5231
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005232 arg = valuePop(ctxt);
5233 if (arg == NULL)
5234 XP_ERROR(XPATH_INVALID_OPERAND);
5235 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005236 xmlXPathFreeObject(arg);
5237
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005238 CAST_TO_NUMBER;
5239 CHECK_TYPE(XPATH_NUMBER);
5240 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005241}
5242
5243/**
5244 * xmlXPathMultValues:
5245 * @ctxt: the XPath Parser context
5246 *
5247 * Implement the multiply operation on XPath objects:
5248 * The numeric operators convert their operands to numbers as if
5249 * by calling the number function.
5250 */
5251void
5252xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5253 xmlXPathObjectPtr arg;
5254 double val;
5255
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005256 arg = valuePop(ctxt);
5257 if (arg == NULL)
5258 XP_ERROR(XPATH_INVALID_OPERAND);
5259 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005260 xmlXPathFreeObject(arg);
5261
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005262 CAST_TO_NUMBER;
5263 CHECK_TYPE(XPATH_NUMBER);
5264 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005265}
5266
5267/**
5268 * xmlXPathDivValues:
5269 * @ctxt: the XPath Parser context
5270 *
5271 * Implement the div operation on XPath objects @arg1 / @arg2:
5272 * The numeric operators convert their operands to numbers as if
5273 * by calling the number function.
5274 */
5275void
5276xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5277 xmlXPathObjectPtr arg;
5278 double val;
5279
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005280 arg = valuePop(ctxt);
5281 if (arg == NULL)
5282 XP_ERROR(XPATH_INVALID_OPERAND);
5283 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005284 xmlXPathFreeObject(arg);
5285
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005286 CAST_TO_NUMBER;
5287 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005288 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5289 ctxt->value->floatval = xmlXPathNAN;
5290 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005291 if (ctxt->value->floatval == 0)
5292 ctxt->value->floatval = xmlXPathNAN;
5293 else if (ctxt->value->floatval > 0)
5294 ctxt->value->floatval = xmlXPathNINF;
5295 else if (ctxt->value->floatval < 0)
5296 ctxt->value->floatval = xmlXPathPINF;
5297 }
5298 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005299 if (ctxt->value->floatval == 0)
5300 ctxt->value->floatval = xmlXPathNAN;
5301 else if (ctxt->value->floatval > 0)
5302 ctxt->value->floatval = xmlXPathPINF;
5303 else if (ctxt->value->floatval < 0)
5304 ctxt->value->floatval = xmlXPathNINF;
5305 } else
5306 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005307}
5308
5309/**
5310 * xmlXPathModValues:
5311 * @ctxt: the XPath Parser context
5312 *
5313 * Implement the mod operation on XPath objects: @arg1 / @arg2
5314 * The numeric operators convert their operands to numbers as if
5315 * by calling the number function.
5316 */
5317void
5318xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5319 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005320 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005321
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005322 arg = valuePop(ctxt);
5323 if (arg == NULL)
5324 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005325 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005326 xmlXPathFreeObject(arg);
5327
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005328 CAST_TO_NUMBER;
5329 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005330 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005331 if (arg2 == 0)
5332 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005333 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005334 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005335 }
Owen Taylor3473f882001-02-23 17:55:21 +00005336}
5337
5338/************************************************************************
5339 * *
5340 * The traversal functions *
5341 * *
5342 ************************************************************************/
5343
Owen Taylor3473f882001-02-23 17:55:21 +00005344/*
5345 * A traversal function enumerates nodes along an axis.
5346 * Initially it must be called with NULL, and it indicates
5347 * termination on the axis by returning NULL.
5348 */
5349typedef xmlNodePtr (*xmlXPathTraversalFunction)
5350 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5351
5352/**
5353 * xmlXPathNextSelf:
5354 * @ctxt: the XPath Parser context
5355 * @cur: the current node in the traversal
5356 *
5357 * Traversal function for the "self" direction
5358 * The self axis contains just the context node itself
5359 *
5360 * Returns the next element following that axis
5361 */
5362xmlNodePtr
5363xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005364 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005365 if (cur == NULL)
5366 return(ctxt->context->node);
5367 return(NULL);
5368}
5369
5370/**
5371 * xmlXPathNextChild:
5372 * @ctxt: the XPath Parser context
5373 * @cur: the current node in the traversal
5374 *
5375 * Traversal function for the "child" direction
5376 * The child axis contains the children of the context node in document order.
5377 *
5378 * Returns the next element following that axis
5379 */
5380xmlNodePtr
5381xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005382 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005383 if (cur == NULL) {
5384 if (ctxt->context->node == NULL) return(NULL);
5385 switch (ctxt->context->node->type) {
5386 case XML_ELEMENT_NODE:
5387 case XML_TEXT_NODE:
5388 case XML_CDATA_SECTION_NODE:
5389 case XML_ENTITY_REF_NODE:
5390 case XML_ENTITY_NODE:
5391 case XML_PI_NODE:
5392 case XML_COMMENT_NODE:
5393 case XML_NOTATION_NODE:
5394 case XML_DTD_NODE:
5395 return(ctxt->context->node->children);
5396 case XML_DOCUMENT_NODE:
5397 case XML_DOCUMENT_TYPE_NODE:
5398 case XML_DOCUMENT_FRAG_NODE:
5399 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005400#ifdef LIBXML_DOCB_ENABLED
5401 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005402#endif
5403 return(((xmlDocPtr) ctxt->context->node)->children);
5404 case XML_ELEMENT_DECL:
5405 case XML_ATTRIBUTE_DECL:
5406 case XML_ENTITY_DECL:
5407 case XML_ATTRIBUTE_NODE:
5408 case XML_NAMESPACE_DECL:
5409 case XML_XINCLUDE_START:
5410 case XML_XINCLUDE_END:
5411 return(NULL);
5412 }
5413 return(NULL);
5414 }
5415 if ((cur->type == XML_DOCUMENT_NODE) ||
5416 (cur->type == XML_HTML_DOCUMENT_NODE))
5417 return(NULL);
5418 return(cur->next);
5419}
5420
5421/**
5422 * xmlXPathNextDescendant:
5423 * @ctxt: the XPath Parser context
5424 * @cur: the current node in the traversal
5425 *
5426 * Traversal function for the "descendant" direction
5427 * the descendant axis contains the descendants of the context node in document
5428 * order; a descendant is a child or a child of a child and so on.
5429 *
5430 * Returns the next element following that axis
5431 */
5432xmlNodePtr
5433xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005434 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005435 if (cur == NULL) {
5436 if (ctxt->context->node == NULL)
5437 return(NULL);
5438 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5439 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5440 return(NULL);
5441
5442 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5443 return(ctxt->context->doc->children);
5444 return(ctxt->context->node->children);
5445 }
5446
Daniel Veillard567e1b42001-08-01 15:53:47 +00005447 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005448 /*
5449 * Do not descend on entities declarations
5450 */
5451 if (cur->children->type != XML_ENTITY_DECL) {
5452 cur = cur->children;
5453 /*
5454 * Skip DTDs
5455 */
5456 if (cur->type != XML_DTD_NODE)
5457 return(cur);
5458 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005459 }
5460
5461 if (cur == ctxt->context->node) return(NULL);
5462
Daniel Veillard68e9e742002-11-16 15:35:11 +00005463 while (cur->next != NULL) {
5464 cur = cur->next;
5465 if ((cur->type != XML_ENTITY_DECL) &&
5466 (cur->type != XML_DTD_NODE))
5467 return(cur);
5468 }
Owen Taylor3473f882001-02-23 17:55:21 +00005469
5470 do {
5471 cur = cur->parent;
5472 if (cur == NULL) return(NULL);
5473 if (cur == ctxt->context->node) return(NULL);
5474 if (cur->next != NULL) {
5475 cur = cur->next;
5476 return(cur);
5477 }
5478 } while (cur != NULL);
5479 return(cur);
5480}
5481
5482/**
5483 * xmlXPathNextDescendantOrSelf:
5484 * @ctxt: the XPath Parser context
5485 * @cur: the current node in the traversal
5486 *
5487 * Traversal function for the "descendant-or-self" direction
5488 * the descendant-or-self axis contains the context node and the descendants
5489 * of the context node in document order; thus the context node is the first
5490 * node on the axis, and the first child of the context node is the second node
5491 * on the axis
5492 *
5493 * Returns the next element following that axis
5494 */
5495xmlNodePtr
5496xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005497 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005498 if (cur == NULL) {
5499 if (ctxt->context->node == NULL)
5500 return(NULL);
5501 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5502 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5503 return(NULL);
5504 return(ctxt->context->node);
5505 }
5506
5507 return(xmlXPathNextDescendant(ctxt, cur));
5508}
5509
5510/**
5511 * xmlXPathNextParent:
5512 * @ctxt: the XPath Parser context
5513 * @cur: the current node in the traversal
5514 *
5515 * Traversal function for the "parent" direction
5516 * The parent axis contains the parent of the context node, if there is one.
5517 *
5518 * Returns the next element following that axis
5519 */
5520xmlNodePtr
5521xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005522 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005523 /*
5524 * the parent of an attribute or namespace node is the element
5525 * to which the attribute or namespace node is attached
5526 * Namespace handling !!!
5527 */
5528 if (cur == NULL) {
5529 if (ctxt->context->node == NULL) return(NULL);
5530 switch (ctxt->context->node->type) {
5531 case XML_ELEMENT_NODE:
5532 case XML_TEXT_NODE:
5533 case XML_CDATA_SECTION_NODE:
5534 case XML_ENTITY_REF_NODE:
5535 case XML_ENTITY_NODE:
5536 case XML_PI_NODE:
5537 case XML_COMMENT_NODE:
5538 case XML_NOTATION_NODE:
5539 case XML_DTD_NODE:
5540 case XML_ELEMENT_DECL:
5541 case XML_ATTRIBUTE_DECL:
5542 case XML_XINCLUDE_START:
5543 case XML_XINCLUDE_END:
5544 case XML_ENTITY_DECL:
5545 if (ctxt->context->node->parent == NULL)
5546 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005547 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005548 ((ctxt->context->node->parent->name[0] == ' ') ||
5549 (xmlStrEqual(ctxt->context->node->parent->name,
5550 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005551 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005552 return(ctxt->context->node->parent);
5553 case XML_ATTRIBUTE_NODE: {
5554 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5555
5556 return(att->parent);
5557 }
5558 case XML_DOCUMENT_NODE:
5559 case XML_DOCUMENT_TYPE_NODE:
5560 case XML_DOCUMENT_FRAG_NODE:
5561 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005562#ifdef LIBXML_DOCB_ENABLED
5563 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005564#endif
5565 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005566 case XML_NAMESPACE_DECL: {
5567 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5568
5569 if ((ns->next != NULL) &&
5570 (ns->next->type != XML_NAMESPACE_DECL))
5571 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005572 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005573 }
Owen Taylor3473f882001-02-23 17:55:21 +00005574 }
5575 }
5576 return(NULL);
5577}
5578
5579/**
5580 * xmlXPathNextAncestor:
5581 * @ctxt: the XPath Parser context
5582 * @cur: the current node in the traversal
5583 *
5584 * Traversal function for the "ancestor" direction
5585 * the ancestor axis contains the ancestors of the context node; the ancestors
5586 * of the context node consist of the parent of context node and the parent's
5587 * parent and so on; the nodes are ordered in reverse document order; thus the
5588 * parent is the first node on the axis, and the parent's parent is the second
5589 * node on the axis
5590 *
5591 * Returns the next element following that axis
5592 */
5593xmlNodePtr
5594xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005595 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005596 /*
5597 * the parent of an attribute or namespace node is the element
5598 * to which the attribute or namespace node is attached
5599 * !!!!!!!!!!!!!
5600 */
5601 if (cur == NULL) {
5602 if (ctxt->context->node == NULL) return(NULL);
5603 switch (ctxt->context->node->type) {
5604 case XML_ELEMENT_NODE:
5605 case XML_TEXT_NODE:
5606 case XML_CDATA_SECTION_NODE:
5607 case XML_ENTITY_REF_NODE:
5608 case XML_ENTITY_NODE:
5609 case XML_PI_NODE:
5610 case XML_COMMENT_NODE:
5611 case XML_DTD_NODE:
5612 case XML_ELEMENT_DECL:
5613 case XML_ATTRIBUTE_DECL:
5614 case XML_ENTITY_DECL:
5615 case XML_NOTATION_NODE:
5616 case XML_XINCLUDE_START:
5617 case XML_XINCLUDE_END:
5618 if (ctxt->context->node->parent == NULL)
5619 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005620 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005621 ((ctxt->context->node->parent->name[0] == ' ') ||
5622 (xmlStrEqual(ctxt->context->node->parent->name,
5623 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005624 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005625 return(ctxt->context->node->parent);
5626 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005627 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005628
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005629 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005630 }
5631 case XML_DOCUMENT_NODE:
5632 case XML_DOCUMENT_TYPE_NODE:
5633 case XML_DOCUMENT_FRAG_NODE:
5634 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005635#ifdef LIBXML_DOCB_ENABLED
5636 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005637#endif
5638 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005639 case XML_NAMESPACE_DECL: {
5640 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5641
5642 if ((ns->next != NULL) &&
5643 (ns->next->type != XML_NAMESPACE_DECL))
5644 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005645 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005646 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005647 }
Owen Taylor3473f882001-02-23 17:55:21 +00005648 }
5649 return(NULL);
5650 }
5651 if (cur == ctxt->context->doc->children)
5652 return((xmlNodePtr) ctxt->context->doc);
5653 if (cur == (xmlNodePtr) ctxt->context->doc)
5654 return(NULL);
5655 switch (cur->type) {
5656 case XML_ELEMENT_NODE:
5657 case XML_TEXT_NODE:
5658 case XML_CDATA_SECTION_NODE:
5659 case XML_ENTITY_REF_NODE:
5660 case XML_ENTITY_NODE:
5661 case XML_PI_NODE:
5662 case XML_COMMENT_NODE:
5663 case XML_NOTATION_NODE:
5664 case XML_DTD_NODE:
5665 case XML_ELEMENT_DECL:
5666 case XML_ATTRIBUTE_DECL:
5667 case XML_ENTITY_DECL:
5668 case XML_XINCLUDE_START:
5669 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005670 if (cur->parent == NULL)
5671 return(NULL);
5672 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005673 ((cur->parent->name[0] == ' ') ||
5674 (xmlStrEqual(cur->parent->name,
5675 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005676 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005677 return(cur->parent);
5678 case XML_ATTRIBUTE_NODE: {
5679 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5680
5681 return(att->parent);
5682 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005683 case XML_NAMESPACE_DECL: {
5684 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5685
5686 if ((ns->next != NULL) &&
5687 (ns->next->type != XML_NAMESPACE_DECL))
5688 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005689 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005690 return(NULL);
5691 }
Owen Taylor3473f882001-02-23 17:55:21 +00005692 case XML_DOCUMENT_NODE:
5693 case XML_DOCUMENT_TYPE_NODE:
5694 case XML_DOCUMENT_FRAG_NODE:
5695 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005696#ifdef LIBXML_DOCB_ENABLED
5697 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005698#endif
5699 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005700 }
5701 return(NULL);
5702}
5703
5704/**
5705 * xmlXPathNextAncestorOrSelf:
5706 * @ctxt: the XPath Parser context
5707 * @cur: the current node in the traversal
5708 *
5709 * Traversal function for the "ancestor-or-self" direction
5710 * he ancestor-or-self axis contains the context node and ancestors of
5711 * the context node in reverse document order; thus the context node is
5712 * the first node on the axis, and the context node's parent the second;
5713 * parent here is defined the same as with the parent axis.
5714 *
5715 * Returns the next element following that axis
5716 */
5717xmlNodePtr
5718xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005719 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005720 if (cur == NULL)
5721 return(ctxt->context->node);
5722 return(xmlXPathNextAncestor(ctxt, cur));
5723}
5724
5725/**
5726 * xmlXPathNextFollowingSibling:
5727 * @ctxt: the XPath Parser context
5728 * @cur: the current node in the traversal
5729 *
5730 * Traversal function for the "following-sibling" direction
5731 * The following-sibling axis contains the following siblings of the context
5732 * node in document order.
5733 *
5734 * Returns the next element following that axis
5735 */
5736xmlNodePtr
5737xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005738 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005739 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5740 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5741 return(NULL);
5742 if (cur == (xmlNodePtr) ctxt->context->doc)
5743 return(NULL);
5744 if (cur == NULL)
5745 return(ctxt->context->node->next);
5746 return(cur->next);
5747}
5748
5749/**
5750 * xmlXPathNextPrecedingSibling:
5751 * @ctxt: the XPath Parser context
5752 * @cur: the current node in the traversal
5753 *
5754 * Traversal function for the "preceding-sibling" direction
5755 * The preceding-sibling axis contains the preceding siblings of the context
5756 * node in reverse document order; the first preceding sibling is first on the
5757 * axis; the sibling preceding that node is the second on the axis and so on.
5758 *
5759 * Returns the next element following that axis
5760 */
5761xmlNodePtr
5762xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005763 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005764 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5765 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5766 return(NULL);
5767 if (cur == (xmlNodePtr) ctxt->context->doc)
5768 return(NULL);
5769 if (cur == NULL)
5770 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005771 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5772 cur = cur->prev;
5773 if (cur == NULL)
5774 return(ctxt->context->node->prev);
5775 }
Owen Taylor3473f882001-02-23 17:55:21 +00005776 return(cur->prev);
5777}
5778
5779/**
5780 * xmlXPathNextFollowing:
5781 * @ctxt: the XPath Parser context
5782 * @cur: the current node in the traversal
5783 *
5784 * Traversal function for the "following" direction
5785 * The following axis contains all nodes in the same document as the context
5786 * node that are after the context node in document order, excluding any
5787 * descendants and excluding attribute nodes and namespace nodes; the nodes
5788 * are ordered in document order
5789 *
5790 * Returns the next element following that axis
5791 */
5792xmlNodePtr
5793xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005794 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005795 if (cur != NULL && cur->children != NULL)
5796 return cur->children ;
5797 if (cur == NULL) cur = ctxt->context->node;
5798 if (cur == NULL) return(NULL) ; /* ERROR */
5799 if (cur->next != NULL) return(cur->next) ;
5800 do {
5801 cur = cur->parent;
5802 if (cur == NULL) return(NULL);
5803 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5804 if (cur->next != NULL) return(cur->next);
5805 } while (cur != NULL);
5806 return(cur);
5807}
5808
5809/*
5810 * xmlXPathIsAncestor:
5811 * @ancestor: the ancestor node
5812 * @node: the current node
5813 *
5814 * Check that @ancestor is a @node's ancestor
5815 *
5816 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5817 */
5818static int
5819xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5820 if ((ancestor == NULL) || (node == NULL)) return(0);
5821 /* nodes need to be in the same document */
5822 if (ancestor->doc != node->doc) return(0);
5823 /* avoid searching if ancestor or node is the root node */
5824 if (ancestor == (xmlNodePtr) node->doc) return(1);
5825 if (node == (xmlNodePtr) ancestor->doc) return(0);
5826 while (node->parent != NULL) {
5827 if (node->parent == ancestor)
5828 return(1);
5829 node = node->parent;
5830 }
5831 return(0);
5832}
5833
5834/**
5835 * xmlXPathNextPreceding:
5836 * @ctxt: the XPath Parser context
5837 * @cur: the current node in the traversal
5838 *
5839 * Traversal function for the "preceding" direction
5840 * the preceding axis contains all nodes in the same document as the context
5841 * node that are before the context node in document order, excluding any
5842 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5843 * ordered in reverse document order
5844 *
5845 * Returns the next element following that axis
5846 */
5847xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005848xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5849{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005850 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005851 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005852 cur = ctxt->context->node;
5853 if (cur == NULL)
5854 return (NULL);
5855 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5856 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005857 do {
5858 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005859 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5860 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005861 }
5862
5863 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005864 if (cur == NULL)
5865 return (NULL);
5866 if (cur == ctxt->context->doc->children)
5867 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005868 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005869 return (cur);
5870}
5871
5872/**
5873 * xmlXPathNextPrecedingInternal:
5874 * @ctxt: the XPath Parser context
5875 * @cur: the current node in the traversal
5876 *
5877 * Traversal function for the "preceding" direction
5878 * the preceding axis contains all nodes in the same document as the context
5879 * node that are before the context node in document order, excluding any
5880 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5881 * ordered in reverse document order
5882 * This is a faster implementation but internal only since it requires a
5883 * state kept in the parser context: ctxt->ancestor.
5884 *
5885 * Returns the next element following that axis
5886 */
5887static xmlNodePtr
5888xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5889 xmlNodePtr cur)
5890{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005891 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005892 if (cur == NULL) {
5893 cur = ctxt->context->node;
5894 if (cur == NULL)
5895 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005896 if (cur->type == XML_NAMESPACE_DECL)
5897 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005898 ctxt->ancestor = cur->parent;
5899 }
5900 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5901 cur = cur->prev;
5902 while (cur->prev == NULL) {
5903 cur = cur->parent;
5904 if (cur == NULL)
5905 return (NULL);
5906 if (cur == ctxt->context->doc->children)
5907 return (NULL);
5908 if (cur != ctxt->ancestor)
5909 return (cur);
5910 ctxt->ancestor = cur->parent;
5911 }
5912 cur = cur->prev;
5913 while (cur->last != NULL)
5914 cur = cur->last;
5915 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005916}
5917
5918/**
5919 * xmlXPathNextNamespace:
5920 * @ctxt: the XPath Parser context
5921 * @cur: the current attribute in the traversal
5922 *
5923 * Traversal function for the "namespace" direction
5924 * the namespace axis contains the namespace nodes of the context node;
5925 * the order of nodes on this axis is implementation-defined; the axis will
5926 * be empty unless the context node is an element
5927 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005928 * We keep the XML namespace node at the end of the list.
5929 *
Owen Taylor3473f882001-02-23 17:55:21 +00005930 * Returns the next element following that axis
5931 */
5932xmlNodePtr
5933xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005934 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005935 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005936 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005937 if (ctxt->context->tmpNsList != NULL)
5938 xmlFree(ctxt->context->tmpNsList);
5939 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005940 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005941 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005942 if (ctxt->context->tmpNsList != NULL) {
5943 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5944 ctxt->context->tmpNsNr++;
5945 }
5946 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005947 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005948 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005949 if (ctxt->context->tmpNsNr > 0) {
5950 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5951 } else {
5952 if (ctxt->context->tmpNsList != NULL)
5953 xmlFree(ctxt->context->tmpNsList);
5954 ctxt->context->tmpNsList = NULL;
5955 return(NULL);
5956 }
Owen Taylor3473f882001-02-23 17:55:21 +00005957}
5958
5959/**
5960 * xmlXPathNextAttribute:
5961 * @ctxt: the XPath Parser context
5962 * @cur: the current attribute in the traversal
5963 *
5964 * Traversal function for the "attribute" direction
5965 * TODO: support DTD inherited default attributes
5966 *
5967 * Returns the next element following that axis
5968 */
5969xmlNodePtr
5970xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005971 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00005972 if (ctxt->context->node == NULL)
5973 return(NULL);
5974 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5975 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005976 if (cur == NULL) {
5977 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5978 return(NULL);
5979 return((xmlNodePtr)ctxt->context->node->properties);
5980 }
5981 return((xmlNodePtr)cur->next);
5982}
5983
5984/************************************************************************
5985 * *
5986 * NodeTest Functions *
5987 * *
5988 ************************************************************************/
5989
Owen Taylor3473f882001-02-23 17:55:21 +00005990#define IS_FUNCTION 200
5991
Owen Taylor3473f882001-02-23 17:55:21 +00005992
5993/************************************************************************
5994 * *
5995 * Implicit tree core function library *
5996 * *
5997 ************************************************************************/
5998
5999/**
6000 * xmlXPathRoot:
6001 * @ctxt: the XPath Parser context
6002 *
6003 * Initialize the context to the root of the document
6004 */
6005void
6006xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006007 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006008 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
6009 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6010}
6011
6012/************************************************************************
6013 * *
6014 * The explicit core function library *
6015 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
6016 * *
6017 ************************************************************************/
6018
6019
6020/**
6021 * xmlXPathLastFunction:
6022 * @ctxt: the XPath Parser context
6023 * @nargs: the number of arguments
6024 *
6025 * Implement the last() XPath function
6026 * number last()
6027 * The last function returns the number of nodes in the context node list.
6028 */
6029void
6030xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6031 CHECK_ARITY(0);
6032 if (ctxt->context->contextSize >= 0) {
6033 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
6034#ifdef DEBUG_EXPR
6035 xmlGenericError(xmlGenericErrorContext,
6036 "last() : %d\n", ctxt->context->contextSize);
6037#endif
6038 } else {
6039 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6040 }
6041}
6042
6043/**
6044 * xmlXPathPositionFunction:
6045 * @ctxt: the XPath Parser context
6046 * @nargs: the number of arguments
6047 *
6048 * Implement the position() XPath function
6049 * number position()
6050 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006051 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00006052 * will be equal to last().
6053 */
6054void
6055xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6056 CHECK_ARITY(0);
6057 if (ctxt->context->proximityPosition >= 0) {
6058 valuePush(ctxt,
6059 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6060#ifdef DEBUG_EXPR
6061 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6062 ctxt->context->proximityPosition);
6063#endif
6064 } else {
6065 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6066 }
6067}
6068
6069/**
6070 * xmlXPathCountFunction:
6071 * @ctxt: the XPath Parser context
6072 * @nargs: the number of arguments
6073 *
6074 * Implement the count() XPath function
6075 * number count(node-set)
6076 */
6077void
6078xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6079 xmlXPathObjectPtr cur;
6080
6081 CHECK_ARITY(1);
6082 if ((ctxt->value == NULL) ||
6083 ((ctxt->value->type != XPATH_NODESET) &&
6084 (ctxt->value->type != XPATH_XSLT_TREE)))
6085 XP_ERROR(XPATH_INVALID_TYPE);
6086 cur = valuePop(ctxt);
6087
Daniel Veillard911f49a2001-04-07 15:39:35 +00006088 if ((cur == NULL) || (cur->nodesetval == NULL))
6089 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006090 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006091 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006092 } else {
6093 if ((cur->nodesetval->nodeNr != 1) ||
6094 (cur->nodesetval->nodeTab == NULL)) {
6095 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6096 } else {
6097 xmlNodePtr tmp;
6098 int i = 0;
6099
6100 tmp = cur->nodesetval->nodeTab[0];
6101 if (tmp != NULL) {
6102 tmp = tmp->children;
6103 while (tmp != NULL) {
6104 tmp = tmp->next;
6105 i++;
6106 }
6107 }
6108 valuePush(ctxt, xmlXPathNewFloat((double) i));
6109 }
6110 }
Owen Taylor3473f882001-02-23 17:55:21 +00006111 xmlXPathFreeObject(cur);
6112}
6113
6114/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006115 * xmlXPathGetElementsByIds:
6116 * @doc: the document
6117 * @ids: a whitespace separated list of IDs
6118 *
6119 * Selects elements by their unique ID.
6120 *
6121 * Returns a node-set of selected elements.
6122 */
6123static xmlNodeSetPtr
6124xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6125 xmlNodeSetPtr ret;
6126 const xmlChar *cur = ids;
6127 xmlChar *ID;
6128 xmlAttrPtr attr;
6129 xmlNodePtr elem = NULL;
6130
Daniel Veillard7a985a12003-07-06 17:57:42 +00006131 if (ids == NULL) return(NULL);
6132
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006133 ret = xmlXPathNodeSetCreate(NULL);
6134
William M. Brack76e95df2003-10-18 16:20:14 +00006135 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006136 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006137 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006138 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006139
6140 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006141 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00006142 /*
6143 * We used to check the fact that the value passed
6144 * was an NCName, but this generated much troubles for
6145 * me and Aleksey Sanin, people blatantly violated that
6146 * constaint, like Visa3D spec.
6147 * if (xmlValidateNCName(ID, 1) == 0)
6148 */
6149 attr = xmlGetID(doc, ID);
6150 if (attr != NULL) {
6151 if (attr->type == XML_ATTRIBUTE_NODE)
6152 elem = attr->parent;
6153 else if (attr->type == XML_ELEMENT_NODE)
6154 elem = (xmlNodePtr) attr;
6155 else
6156 elem = NULL;
6157 if (elem != NULL)
6158 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00006159 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006160 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006161 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006162
William M. Brack76e95df2003-10-18 16:20:14 +00006163 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006164 ids = cur;
6165 }
6166 return(ret);
6167}
6168
6169/**
Owen Taylor3473f882001-02-23 17:55:21 +00006170 * xmlXPathIdFunction:
6171 * @ctxt: the XPath Parser context
6172 * @nargs: the number of arguments
6173 *
6174 * Implement the id() XPath function
6175 * node-set id(object)
6176 * The id function selects elements by their unique ID
6177 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6178 * then the result is the union of the result of applying id to the
6179 * string value of each of the nodes in the argument node-set. When the
6180 * argument to id is of any other type, the argument is converted to a
6181 * string as if by a call to the string function; the string is split
6182 * into a whitespace-separated list of tokens (whitespace is any sequence
6183 * of characters matching the production S); the result is a node-set
6184 * containing the elements in the same document as the context node that
6185 * have a unique ID equal to any of the tokens in the list.
6186 */
6187void
6188xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006189 xmlChar *tokens;
6190 xmlNodeSetPtr ret;
6191 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006192
6193 CHECK_ARITY(1);
6194 obj = valuePop(ctxt);
6195 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006196 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006197 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006198 int i;
6199
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006200 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006201
Daniel Veillard911f49a2001-04-07 15:39:35 +00006202 if (obj->nodesetval != NULL) {
6203 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006204 tokens =
6205 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6206 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6207 ret = xmlXPathNodeSetMerge(ret, ns);
6208 xmlXPathFreeNodeSet(ns);
6209 if (tokens != NULL)
6210 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006211 }
Owen Taylor3473f882001-02-23 17:55:21 +00006212 }
6213
6214 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006215 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006216 return;
6217 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006218 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006219
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006220 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6221 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006222
Owen Taylor3473f882001-02-23 17:55:21 +00006223 xmlXPathFreeObject(obj);
6224 return;
6225}
6226
6227/**
6228 * xmlXPathLocalNameFunction:
6229 * @ctxt: the XPath Parser context
6230 * @nargs: the number of arguments
6231 *
6232 * Implement the local-name() XPath function
6233 * string local-name(node-set?)
6234 * The local-name function returns a string containing the local part
6235 * of the name of the node in the argument node-set that is first in
6236 * document order. If the node-set is empty or the first node has no
6237 * name, an empty string is returned. If the argument is omitted it
6238 * defaults to the context node.
6239 */
6240void
6241xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6242 xmlXPathObjectPtr cur;
6243
Daniel Veillarda82b1822004-11-08 16:24:57 +00006244 if (ctxt == NULL) return;
6245
Owen Taylor3473f882001-02-23 17:55:21 +00006246 if (nargs == 0) {
6247 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6248 nargs = 1;
6249 }
6250
6251 CHECK_ARITY(1);
6252 if ((ctxt->value == NULL) ||
6253 ((ctxt->value->type != XPATH_NODESET) &&
6254 (ctxt->value->type != XPATH_XSLT_TREE)))
6255 XP_ERROR(XPATH_INVALID_TYPE);
6256 cur = valuePop(ctxt);
6257
Daniel Veillard911f49a2001-04-07 15:39:35 +00006258 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006259 valuePush(ctxt, xmlXPathNewCString(""));
6260 } else {
6261 int i = 0; /* Should be first in document order !!!!! */
6262 switch (cur->nodesetval->nodeTab[i]->type) {
6263 case XML_ELEMENT_NODE:
6264 case XML_ATTRIBUTE_NODE:
6265 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006266 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6267 valuePush(ctxt, xmlXPathNewCString(""));
6268 else
6269 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006270 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6271 break;
6272 case XML_NAMESPACE_DECL:
6273 valuePush(ctxt, xmlXPathNewString(
6274 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6275 break;
6276 default:
6277 valuePush(ctxt, xmlXPathNewCString(""));
6278 }
6279 }
6280 xmlXPathFreeObject(cur);
6281}
6282
6283/**
6284 * xmlXPathNamespaceURIFunction:
6285 * @ctxt: the XPath Parser context
6286 * @nargs: the number of arguments
6287 *
6288 * Implement the namespace-uri() XPath function
6289 * string namespace-uri(node-set?)
6290 * The namespace-uri function returns a string containing the
6291 * namespace URI of the expanded name of the node in the argument
6292 * node-set that is first in document order. If the node-set is empty,
6293 * the first node has no name, or the expanded name has no namespace
6294 * URI, an empty string is returned. If the argument is omitted it
6295 * defaults to the context node.
6296 */
6297void
6298xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6299 xmlXPathObjectPtr cur;
6300
Daniel Veillarda82b1822004-11-08 16:24:57 +00006301 if (ctxt == NULL) return;
6302
Owen Taylor3473f882001-02-23 17:55:21 +00006303 if (nargs == 0) {
6304 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6305 nargs = 1;
6306 }
6307 CHECK_ARITY(1);
6308 if ((ctxt->value == NULL) ||
6309 ((ctxt->value->type != XPATH_NODESET) &&
6310 (ctxt->value->type != XPATH_XSLT_TREE)))
6311 XP_ERROR(XPATH_INVALID_TYPE);
6312 cur = valuePop(ctxt);
6313
Daniel Veillard911f49a2001-04-07 15:39:35 +00006314 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006315 valuePush(ctxt, xmlXPathNewCString(""));
6316 } else {
6317 int i = 0; /* Should be first in document order !!!!! */
6318 switch (cur->nodesetval->nodeTab[i]->type) {
6319 case XML_ELEMENT_NODE:
6320 case XML_ATTRIBUTE_NODE:
6321 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6322 valuePush(ctxt, xmlXPathNewCString(""));
6323 else
6324 valuePush(ctxt, xmlXPathNewString(
6325 cur->nodesetval->nodeTab[i]->ns->href));
6326 break;
6327 default:
6328 valuePush(ctxt, xmlXPathNewCString(""));
6329 }
6330 }
6331 xmlXPathFreeObject(cur);
6332}
6333
6334/**
6335 * xmlXPathNameFunction:
6336 * @ctxt: the XPath Parser context
6337 * @nargs: the number of arguments
6338 *
6339 * Implement the name() XPath function
6340 * string name(node-set?)
6341 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006342 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006343 * order. The QName must represent the name with respect to the namespace
6344 * declarations in effect on the node whose name is being represented.
6345 * Typically, this will be the form in which the name occurred in the XML
6346 * source. This need not be the case if there are namespace declarations
6347 * in effect on the node that associate multiple prefixes with the same
6348 * namespace. However, an implementation may include information about
6349 * the original prefix in its representation of nodes; in this case, an
6350 * implementation can ensure that the returned string is always the same
6351 * as the QName used in the XML source. If the argument it omitted it
6352 * defaults to the context node.
6353 * Libxml keep the original prefix so the "real qualified name" used is
6354 * returned.
6355 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006356static void
Daniel Veillard04383752001-07-08 14:27:15 +00006357xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6358{
Owen Taylor3473f882001-02-23 17:55:21 +00006359 xmlXPathObjectPtr cur;
6360
6361 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006362 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6363 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006364 }
6365
6366 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006367 if ((ctxt->value == NULL) ||
6368 ((ctxt->value->type != XPATH_NODESET) &&
6369 (ctxt->value->type != XPATH_XSLT_TREE)))
6370 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006371 cur = valuePop(ctxt);
6372
Daniel Veillard911f49a2001-04-07 15:39:35 +00006373 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006374 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006375 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006376 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006377
Daniel Veillard04383752001-07-08 14:27:15 +00006378 switch (cur->nodesetval->nodeTab[i]->type) {
6379 case XML_ELEMENT_NODE:
6380 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006381 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6382 valuePush(ctxt, xmlXPathNewCString(""));
6383 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6384 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006385 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006386 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006387
Daniel Veillard652d8a92003-02-04 19:28:49 +00006388 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006389 xmlChar *fullname;
6390
6391 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6392 cur->nodesetval->nodeTab[i]->ns->prefix,
6393 NULL, 0);
6394 if (fullname == cur->nodesetval->nodeTab[i]->name)
6395 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6396 if (fullname == NULL) {
6397 XP_ERROR(XPATH_MEMORY_ERROR);
6398 }
6399 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006400 }
6401 break;
6402 default:
6403 valuePush(ctxt,
6404 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6405 xmlXPathLocalNameFunction(ctxt, 1);
6406 }
Owen Taylor3473f882001-02-23 17:55:21 +00006407 }
6408 xmlXPathFreeObject(cur);
6409}
6410
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006411
6412/**
Owen Taylor3473f882001-02-23 17:55:21 +00006413 * xmlXPathStringFunction:
6414 * @ctxt: the XPath Parser context
6415 * @nargs: the number of arguments
6416 *
6417 * Implement the string() XPath function
6418 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006419 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006420 * - A node-set is converted to a string by returning the value of
6421 * the node in the node-set that is first in document order.
6422 * If the node-set is empty, an empty string is returned.
6423 * - A number is converted to a string as follows
6424 * + NaN is converted to the string NaN
6425 * + positive zero is converted to the string 0
6426 * + negative zero is converted to the string 0
6427 * + positive infinity is converted to the string Infinity
6428 * + negative infinity is converted to the string -Infinity
6429 * + if the number is an integer, the number is represented in
6430 * decimal form as a Number with no decimal point and no leading
6431 * zeros, preceded by a minus sign (-) if the number is negative
6432 * + otherwise, the number is represented in decimal form as a
6433 * Number including a decimal point with at least one digit
6434 * before the decimal point and at least one digit after the
6435 * decimal point, preceded by a minus sign (-) if the number
6436 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006437 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006438 * before the decimal point; beyond the one required digit
6439 * after the decimal point there must be as many, but only as
6440 * many, more digits as are needed to uniquely distinguish the
6441 * number from all other IEEE 754 numeric values.
6442 * - The boolean false value is converted to the string false.
6443 * The boolean true value is converted to the string true.
6444 *
6445 * If the argument is omitted, it defaults to a node-set with the
6446 * context node as its only member.
6447 */
6448void
6449xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6450 xmlXPathObjectPtr cur;
6451
Daniel Veillarda82b1822004-11-08 16:24:57 +00006452 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006453 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006454 valuePush(ctxt,
6455 xmlXPathWrapString(
6456 xmlXPathCastNodeToString(ctxt->context->node)));
6457 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006458 }
6459
6460 CHECK_ARITY(1);
6461 cur = valuePop(ctxt);
6462 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006463 cur = xmlXPathConvertString(cur);
6464 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006465}
6466
6467/**
6468 * xmlXPathStringLengthFunction:
6469 * @ctxt: the XPath Parser context
6470 * @nargs: the number of arguments
6471 *
6472 * Implement the string-length() XPath function
6473 * number string-length(string?)
6474 * The string-length returns the number of characters in the string
6475 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6476 * the context node converted to a string, in other words the value
6477 * of the context node.
6478 */
6479void
6480xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6481 xmlXPathObjectPtr cur;
6482
6483 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006484 if ((ctxt == NULL) || (ctxt->context == NULL))
6485 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006486 if (ctxt->context->node == NULL) {
6487 valuePush(ctxt, xmlXPathNewFloat(0));
6488 } else {
6489 xmlChar *content;
6490
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006491 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006492 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006493 xmlFree(content);
6494 }
6495 return;
6496 }
6497 CHECK_ARITY(1);
6498 CAST_TO_STRING;
6499 CHECK_TYPE(XPATH_STRING);
6500 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006501 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006502 xmlXPathFreeObject(cur);
6503}
6504
6505/**
6506 * xmlXPathConcatFunction:
6507 * @ctxt: the XPath Parser context
6508 * @nargs: the number of arguments
6509 *
6510 * Implement the concat() XPath function
6511 * string concat(string, string, string*)
6512 * The concat function returns the concatenation of its arguments.
6513 */
6514void
6515xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6516 xmlXPathObjectPtr cur, newobj;
6517 xmlChar *tmp;
6518
Daniel Veillarda82b1822004-11-08 16:24:57 +00006519 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006520 if (nargs < 2) {
6521 CHECK_ARITY(2);
6522 }
6523
6524 CAST_TO_STRING;
6525 cur = valuePop(ctxt);
6526 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6527 xmlXPathFreeObject(cur);
6528 return;
6529 }
6530 nargs--;
6531
6532 while (nargs > 0) {
6533 CAST_TO_STRING;
6534 newobj = valuePop(ctxt);
6535 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6536 xmlXPathFreeObject(newobj);
6537 xmlXPathFreeObject(cur);
6538 XP_ERROR(XPATH_INVALID_TYPE);
6539 }
6540 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6541 newobj->stringval = cur->stringval;
6542 cur->stringval = tmp;
6543
6544 xmlXPathFreeObject(newobj);
6545 nargs--;
6546 }
6547 valuePush(ctxt, cur);
6548}
6549
6550/**
6551 * xmlXPathContainsFunction:
6552 * @ctxt: the XPath Parser context
6553 * @nargs: the number of arguments
6554 *
6555 * Implement the contains() XPath function
6556 * boolean contains(string, string)
6557 * The contains function returns true if the first argument string
6558 * contains the second argument string, and otherwise returns false.
6559 */
6560void
6561xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6562 xmlXPathObjectPtr hay, needle;
6563
6564 CHECK_ARITY(2);
6565 CAST_TO_STRING;
6566 CHECK_TYPE(XPATH_STRING);
6567 needle = valuePop(ctxt);
6568 CAST_TO_STRING;
6569 hay = valuePop(ctxt);
6570 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6571 xmlXPathFreeObject(hay);
6572 xmlXPathFreeObject(needle);
6573 XP_ERROR(XPATH_INVALID_TYPE);
6574 }
6575 if (xmlStrstr(hay->stringval, needle->stringval))
6576 valuePush(ctxt, xmlXPathNewBoolean(1));
6577 else
6578 valuePush(ctxt, xmlXPathNewBoolean(0));
6579 xmlXPathFreeObject(hay);
6580 xmlXPathFreeObject(needle);
6581}
6582
6583/**
6584 * xmlXPathStartsWithFunction:
6585 * @ctxt: the XPath Parser context
6586 * @nargs: the number of arguments
6587 *
6588 * Implement the starts-with() XPath function
6589 * boolean starts-with(string, string)
6590 * The starts-with function returns true if the first argument string
6591 * starts with the second argument string, and otherwise returns false.
6592 */
6593void
6594xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6595 xmlXPathObjectPtr hay, needle;
6596 int n;
6597
6598 CHECK_ARITY(2);
6599 CAST_TO_STRING;
6600 CHECK_TYPE(XPATH_STRING);
6601 needle = valuePop(ctxt);
6602 CAST_TO_STRING;
6603 hay = valuePop(ctxt);
6604 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6605 xmlXPathFreeObject(hay);
6606 xmlXPathFreeObject(needle);
6607 XP_ERROR(XPATH_INVALID_TYPE);
6608 }
6609 n = xmlStrlen(needle->stringval);
6610 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6611 valuePush(ctxt, xmlXPathNewBoolean(0));
6612 else
6613 valuePush(ctxt, xmlXPathNewBoolean(1));
6614 xmlXPathFreeObject(hay);
6615 xmlXPathFreeObject(needle);
6616}
6617
6618/**
6619 * xmlXPathSubstringFunction:
6620 * @ctxt: the XPath Parser context
6621 * @nargs: the number of arguments
6622 *
6623 * Implement the substring() XPath function
6624 * string substring(string, number, number?)
6625 * The substring function returns the substring of the first argument
6626 * starting at the position specified in the second argument with
6627 * length specified in the third argument. For example,
6628 * substring("12345",2,3) returns "234". If the third argument is not
6629 * specified, it returns the substring starting at the position specified
6630 * in the second argument and continuing to the end of the string. For
6631 * example, substring("12345",2) returns "2345". More precisely, each
6632 * character in the string (see [3.6 Strings]) is considered to have a
6633 * numeric position: the position of the first character is 1, the position
6634 * of the second character is 2 and so on. The returned substring contains
6635 * those characters for which the position of the character is greater than
6636 * or equal to the second argument and, if the third argument is specified,
6637 * less than the sum of the second and third arguments; the comparisons
6638 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6639 * - substring("12345", 1.5, 2.6) returns "234"
6640 * - substring("12345", 0, 3) returns "12"
6641 * - substring("12345", 0 div 0, 3) returns ""
6642 * - substring("12345", 1, 0 div 0) returns ""
6643 * - substring("12345", -42, 1 div 0) returns "12345"
6644 * - substring("12345", -1 div 0, 1 div 0) returns ""
6645 */
6646void
6647xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6648 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006649 double le=0, in;
6650 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006651 xmlChar *ret;
6652
Owen Taylor3473f882001-02-23 17:55:21 +00006653 if (nargs < 2) {
6654 CHECK_ARITY(2);
6655 }
6656 if (nargs > 3) {
6657 CHECK_ARITY(3);
6658 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006659 /*
6660 * take care of possible last (position) argument
6661 */
Owen Taylor3473f882001-02-23 17:55:21 +00006662 if (nargs == 3) {
6663 CAST_TO_NUMBER;
6664 CHECK_TYPE(XPATH_NUMBER);
6665 len = valuePop(ctxt);
6666 le = len->floatval;
6667 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006668 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006669
Owen Taylor3473f882001-02-23 17:55:21 +00006670 CAST_TO_NUMBER;
6671 CHECK_TYPE(XPATH_NUMBER);
6672 start = valuePop(ctxt);
6673 in = start->floatval;
6674 xmlXPathFreeObject(start);
6675 CAST_TO_STRING;
6676 CHECK_TYPE(XPATH_STRING);
6677 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006678 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006679
Daniel Veillard97ac1312001-05-30 19:14:17 +00006680 /*
6681 * If last pos not present, calculate last position
6682 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006683 if (nargs != 3) {
6684 le = (double)m;
6685 if (in < 1.0)
6686 in = 1.0;
6687 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006688
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006689 /* Need to check for the special cases where either
6690 * the index is NaN, the length is NaN, or both
6691 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006692 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006693 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006694 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006695 * To meet the requirements of the spec, the arguments
6696 * must be converted to integer format before
6697 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006698 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006699 * First we go to integer form, rounding up
6700 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006701 */
6702 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006703 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006704
Daniel Veillard9e412302002-06-10 15:59:44 +00006705 if (xmlXPathIsInf(le) == 1) {
6706 l = m;
6707 if (i < 1)
6708 i = 1;
6709 }
6710 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6711 l = 0;
6712 else {
6713 l = (int) le;
6714 if (((double)l)+0.5 <= le) l++;
6715 }
6716
6717 /* Now we normalize inidices */
6718 i -= 1;
6719 l += i;
6720 if (i < 0)
6721 i = 0;
6722 if (l > m)
6723 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006724
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006725 /* number of chars to copy */
6726 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006727
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006728 ret = xmlUTF8Strsub(str->stringval, i, l);
6729 }
6730 else {
6731 ret = NULL;
6732 }
6733
Owen Taylor3473f882001-02-23 17:55:21 +00006734 if (ret == NULL)
6735 valuePush(ctxt, xmlXPathNewCString(""));
6736 else {
6737 valuePush(ctxt, xmlXPathNewString(ret));
6738 xmlFree(ret);
6739 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006740
Owen Taylor3473f882001-02-23 17:55:21 +00006741 xmlXPathFreeObject(str);
6742}
6743
6744/**
6745 * xmlXPathSubstringBeforeFunction:
6746 * @ctxt: the XPath Parser context
6747 * @nargs: the number of arguments
6748 *
6749 * Implement the substring-before() XPath function
6750 * string substring-before(string, string)
6751 * The substring-before function returns the substring of the first
6752 * argument string that precedes the first occurrence of the second
6753 * argument string in the first argument string, or the empty string
6754 * if the first argument string does not contain the second argument
6755 * string. For example, substring-before("1999/04/01","/") returns 1999.
6756 */
6757void
6758xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6759 xmlXPathObjectPtr str;
6760 xmlXPathObjectPtr find;
6761 xmlBufferPtr target;
6762 const xmlChar *point;
6763 int offset;
6764
6765 CHECK_ARITY(2);
6766 CAST_TO_STRING;
6767 find = valuePop(ctxt);
6768 CAST_TO_STRING;
6769 str = valuePop(ctxt);
6770
6771 target = xmlBufferCreate();
6772 if (target) {
6773 point = xmlStrstr(str->stringval, find->stringval);
6774 if (point) {
6775 offset = (int)(point - str->stringval);
6776 xmlBufferAdd(target, str->stringval, offset);
6777 }
6778 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6779 xmlBufferFree(target);
6780 }
6781
6782 xmlXPathFreeObject(str);
6783 xmlXPathFreeObject(find);
6784}
6785
6786/**
6787 * xmlXPathSubstringAfterFunction:
6788 * @ctxt: the XPath Parser context
6789 * @nargs: the number of arguments
6790 *
6791 * Implement the substring-after() XPath function
6792 * string substring-after(string, string)
6793 * The substring-after function returns the substring of the first
6794 * argument string that follows the first occurrence of the second
6795 * argument string in the first argument string, or the empty stringi
6796 * if the first argument string does not contain the second argument
6797 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6798 * and substring-after("1999/04/01","19") returns 99/04/01.
6799 */
6800void
6801xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6802 xmlXPathObjectPtr str;
6803 xmlXPathObjectPtr find;
6804 xmlBufferPtr target;
6805 const xmlChar *point;
6806 int offset;
6807
6808 CHECK_ARITY(2);
6809 CAST_TO_STRING;
6810 find = valuePop(ctxt);
6811 CAST_TO_STRING;
6812 str = valuePop(ctxt);
6813
6814 target = xmlBufferCreate();
6815 if (target) {
6816 point = xmlStrstr(str->stringval, find->stringval);
6817 if (point) {
6818 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6819 xmlBufferAdd(target, &str->stringval[offset],
6820 xmlStrlen(str->stringval) - offset);
6821 }
6822 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6823 xmlBufferFree(target);
6824 }
6825
6826 xmlXPathFreeObject(str);
6827 xmlXPathFreeObject(find);
6828}
6829
6830/**
6831 * xmlXPathNormalizeFunction:
6832 * @ctxt: the XPath Parser context
6833 * @nargs: the number of arguments
6834 *
6835 * Implement the normalize-space() XPath function
6836 * string normalize-space(string?)
6837 * The normalize-space function returns the argument string with white
6838 * space normalized by stripping leading and trailing whitespace
6839 * and replacing sequences of whitespace characters by a single
6840 * space. Whitespace characters are the same allowed by the S production
6841 * in XML. If the argument is omitted, it defaults to the context
6842 * node converted to a string, in other words the value of the context node.
6843 */
6844void
6845xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6846 xmlXPathObjectPtr obj = NULL;
6847 xmlChar *source = NULL;
6848 xmlBufferPtr target;
6849 xmlChar blank;
6850
Daniel Veillarda82b1822004-11-08 16:24:57 +00006851 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006852 if (nargs == 0) {
6853 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006854 valuePush(ctxt,
6855 xmlXPathWrapString(
6856 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006857 nargs = 1;
6858 }
6859
6860 CHECK_ARITY(1);
6861 CAST_TO_STRING;
6862 CHECK_TYPE(XPATH_STRING);
6863 obj = valuePop(ctxt);
6864 source = obj->stringval;
6865
6866 target = xmlBufferCreate();
6867 if (target && source) {
6868
6869 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006870 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006871 source++;
6872
6873 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6874 blank = 0;
6875 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006876 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006877 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006878 } else {
6879 if (blank) {
6880 xmlBufferAdd(target, &blank, 1);
6881 blank = 0;
6882 }
6883 xmlBufferAdd(target, source, 1);
6884 }
6885 source++;
6886 }
6887
6888 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6889 xmlBufferFree(target);
6890 }
6891 xmlXPathFreeObject(obj);
6892}
6893
6894/**
6895 * xmlXPathTranslateFunction:
6896 * @ctxt: the XPath Parser context
6897 * @nargs: the number of arguments
6898 *
6899 * Implement the translate() XPath function
6900 * string translate(string, string, string)
6901 * The translate function returns the first argument string with
6902 * occurrences of characters in the second argument string replaced
6903 * by the character at the corresponding position in the third argument
6904 * string. For example, translate("bar","abc","ABC") returns the string
6905 * BAr. If there is a character in the second argument string with no
6906 * character at a corresponding position in the third argument string
6907 * (because the second argument string is longer than the third argument
6908 * string), then occurrences of that character in the first argument
6909 * string are removed. For example, translate("--aaa--","abc-","ABC")
6910 * returns "AAA". If a character occurs more than once in second
6911 * argument string, then the first occurrence determines the replacement
6912 * character. If the third argument string is longer than the second
6913 * argument string, then excess characters are ignored.
6914 */
6915void
6916xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006917 xmlXPathObjectPtr str;
6918 xmlXPathObjectPtr from;
6919 xmlXPathObjectPtr to;
6920 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006921 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006922 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00006923 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006924 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006925
Daniel Veillarde043ee12001-04-16 14:08:07 +00006926 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006927
Daniel Veillarde043ee12001-04-16 14:08:07 +00006928 CAST_TO_STRING;
6929 to = valuePop(ctxt);
6930 CAST_TO_STRING;
6931 from = valuePop(ctxt);
6932 CAST_TO_STRING;
6933 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006934
Daniel Veillarde043ee12001-04-16 14:08:07 +00006935 target = xmlBufferCreate();
6936 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006937 max = xmlUTF8Strlen(to->stringval);
6938 for (cptr = str->stringval; (ch=*cptr); ) {
6939 offset = xmlUTF8Strloc(from->stringval, cptr);
6940 if (offset >= 0) {
6941 if (offset < max) {
6942 point = xmlUTF8Strpos(to->stringval, offset);
6943 if (point)
6944 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6945 }
6946 } else
6947 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6948
6949 /* Step to next character in input */
6950 cptr++;
6951 if ( ch & 0x80 ) {
6952 /* if not simple ascii, verify proper format */
6953 if ( (ch & 0xc0) != 0xc0 ) {
6954 xmlGenericError(xmlGenericErrorContext,
6955 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6956 break;
6957 }
6958 /* then skip over remaining bytes for this char */
6959 while ( (ch <<= 1) & 0x80 )
6960 if ( (*cptr++ & 0xc0) != 0x80 ) {
6961 xmlGenericError(xmlGenericErrorContext,
6962 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6963 break;
6964 }
6965 if (ch & 0x80) /* must have had error encountered */
6966 break;
6967 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006968 }
Owen Taylor3473f882001-02-23 17:55:21 +00006969 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006970 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6971 xmlBufferFree(target);
6972 xmlXPathFreeObject(str);
6973 xmlXPathFreeObject(from);
6974 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006975}
6976
6977/**
6978 * xmlXPathBooleanFunction:
6979 * @ctxt: the XPath Parser context
6980 * @nargs: the number of arguments
6981 *
6982 * Implement the boolean() XPath function
6983 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00006984 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006985 * - a number is true if and only if it is neither positive or
6986 * negative zero nor NaN
6987 * - a node-set is true if and only if it is non-empty
6988 * - a string is true if and only if its length is non-zero
6989 */
6990void
6991xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6992 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006993
6994 CHECK_ARITY(1);
6995 cur = valuePop(ctxt);
6996 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006997 cur = xmlXPathConvertBoolean(cur);
6998 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006999}
7000
7001/**
7002 * xmlXPathNotFunction:
7003 * @ctxt: the XPath Parser context
7004 * @nargs: the number of arguments
7005 *
7006 * Implement the not() XPath function
7007 * boolean not(boolean)
7008 * The not function returns true if its argument is false,
7009 * and false otherwise.
7010 */
7011void
7012xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7013 CHECK_ARITY(1);
7014 CAST_TO_BOOLEAN;
7015 CHECK_TYPE(XPATH_BOOLEAN);
7016 ctxt->value->boolval = ! ctxt->value->boolval;
7017}
7018
7019/**
7020 * xmlXPathTrueFunction:
7021 * @ctxt: the XPath Parser context
7022 * @nargs: the number of arguments
7023 *
7024 * Implement the true() XPath function
7025 * boolean true()
7026 */
7027void
7028xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7029 CHECK_ARITY(0);
7030 valuePush(ctxt, xmlXPathNewBoolean(1));
7031}
7032
7033/**
7034 * xmlXPathFalseFunction:
7035 * @ctxt: the XPath Parser context
7036 * @nargs: the number of arguments
7037 *
7038 * Implement the false() XPath function
7039 * boolean false()
7040 */
7041void
7042xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7043 CHECK_ARITY(0);
7044 valuePush(ctxt, xmlXPathNewBoolean(0));
7045}
7046
7047/**
7048 * xmlXPathLangFunction:
7049 * @ctxt: the XPath Parser context
7050 * @nargs: the number of arguments
7051 *
7052 * Implement the lang() XPath function
7053 * boolean lang(string)
7054 * The lang function returns true or false depending on whether the
7055 * language of the context node as specified by xml:lang attributes
7056 * is the same as or is a sublanguage of the language specified by
7057 * the argument string. The language of the context node is determined
7058 * by the value of the xml:lang attribute on the context node, or, if
7059 * the context node has no xml:lang attribute, by the value of the
7060 * xml:lang attribute on the nearest ancestor of the context node that
7061 * has an xml:lang attribute. If there is no such attribute, then lang
7062 * returns false. If there is such an attribute, then lang returns
7063 * true if the attribute value is equal to the argument ignoring case,
7064 * or if there is some suffix starting with - such that the attribute
7065 * value is equal to the argument ignoring that suffix of the attribute
7066 * value and ignoring case.
7067 */
7068void
7069xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7070 xmlXPathObjectPtr val;
7071 const xmlChar *theLang;
7072 const xmlChar *lang;
7073 int ret = 0;
7074 int i;
7075
7076 CHECK_ARITY(1);
7077 CAST_TO_STRING;
7078 CHECK_TYPE(XPATH_STRING);
7079 val = valuePop(ctxt);
7080 lang = val->stringval;
7081 theLang = xmlNodeGetLang(ctxt->context->node);
7082 if ((theLang != NULL) && (lang != NULL)) {
7083 for (i = 0;lang[i] != 0;i++)
7084 if (toupper(lang[i]) != toupper(theLang[i]))
7085 goto not_equal;
7086 ret = 1;
7087 }
7088not_equal:
William M. Bracka59ddb52004-02-25 08:12:32 +00007089 xmlFree((void *)theLang);
Owen Taylor3473f882001-02-23 17:55:21 +00007090 xmlXPathFreeObject(val);
7091 valuePush(ctxt, xmlXPathNewBoolean(ret));
7092}
7093
7094/**
7095 * xmlXPathNumberFunction:
7096 * @ctxt: the XPath Parser context
7097 * @nargs: the number of arguments
7098 *
7099 * Implement the number() XPath function
7100 * number number(object?)
7101 */
7102void
7103xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7104 xmlXPathObjectPtr cur;
7105 double res;
7106
Daniel Veillarda82b1822004-11-08 16:24:57 +00007107 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007108 if (nargs == 0) {
7109 if (ctxt->context->node == NULL) {
7110 valuePush(ctxt, xmlXPathNewFloat(0.0));
7111 } else {
7112 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7113
7114 res = xmlXPathStringEvalNumber(content);
7115 valuePush(ctxt, xmlXPathNewFloat(res));
7116 xmlFree(content);
7117 }
7118 return;
7119 }
7120
7121 CHECK_ARITY(1);
7122 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007123 cur = xmlXPathConvertNumber(cur);
7124 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007125}
7126
7127/**
7128 * xmlXPathSumFunction:
7129 * @ctxt: the XPath Parser context
7130 * @nargs: the number of arguments
7131 *
7132 * Implement the sum() XPath function
7133 * number sum(node-set)
7134 * The sum function returns the sum of the values of the nodes in
7135 * the argument node-set.
7136 */
7137void
7138xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7139 xmlXPathObjectPtr cur;
7140 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007141 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007142
7143 CHECK_ARITY(1);
7144 if ((ctxt->value == NULL) ||
7145 ((ctxt->value->type != XPATH_NODESET) &&
7146 (ctxt->value->type != XPATH_XSLT_TREE)))
7147 XP_ERROR(XPATH_INVALID_TYPE);
7148 cur = valuePop(ctxt);
7149
William M. Brack08171912003-12-29 02:52:11 +00007150 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007151 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7152 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007153 }
7154 }
William M. Brack08171912003-12-29 02:52:11 +00007155 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007156 xmlXPathFreeObject(cur);
7157}
7158
7159/**
7160 * xmlXPathFloorFunction:
7161 * @ctxt: the XPath Parser context
7162 * @nargs: the number of arguments
7163 *
7164 * Implement the floor() XPath function
7165 * number floor(number)
7166 * The floor function returns the largest (closest to positive infinity)
7167 * number that is not greater than the argument and that is an integer.
7168 */
7169void
7170xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007171 double f;
7172
Owen Taylor3473f882001-02-23 17:55:21 +00007173 CHECK_ARITY(1);
7174 CAST_TO_NUMBER;
7175 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007176
7177 f = (double)((int) ctxt->value->floatval);
7178 if (f != ctxt->value->floatval) {
7179 if (ctxt->value->floatval > 0)
7180 ctxt->value->floatval = f;
7181 else
7182 ctxt->value->floatval = f - 1;
7183 }
Owen Taylor3473f882001-02-23 17:55:21 +00007184}
7185
7186/**
7187 * xmlXPathCeilingFunction:
7188 * @ctxt: the XPath Parser context
7189 * @nargs: the number of arguments
7190 *
7191 * Implement the ceiling() XPath function
7192 * number ceiling(number)
7193 * The ceiling function returns the smallest (closest to negative infinity)
7194 * number that is not less than the argument and that is an integer.
7195 */
7196void
7197xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7198 double f;
7199
7200 CHECK_ARITY(1);
7201 CAST_TO_NUMBER;
7202 CHECK_TYPE(XPATH_NUMBER);
7203
7204#if 0
7205 ctxt->value->floatval = ceil(ctxt->value->floatval);
7206#else
7207 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007208 if (f != ctxt->value->floatval) {
7209 if (ctxt->value->floatval > 0)
7210 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007211 else {
7212 if (ctxt->value->floatval < 0 && f == 0)
7213 ctxt->value->floatval = xmlXPathNZERO;
7214 else
7215 ctxt->value->floatval = f;
7216 }
7217
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007218 }
Owen Taylor3473f882001-02-23 17:55:21 +00007219#endif
7220}
7221
7222/**
7223 * xmlXPathRoundFunction:
7224 * @ctxt: the XPath Parser context
7225 * @nargs: the number of arguments
7226 *
7227 * Implement the round() XPath function
7228 * number round(number)
7229 * The round function returns the number that is closest to the
7230 * argument and that is an integer. If there are two such numbers,
7231 * then the one that is even is returned.
7232 */
7233void
7234xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7235 double f;
7236
7237 CHECK_ARITY(1);
7238 CAST_TO_NUMBER;
7239 CHECK_TYPE(XPATH_NUMBER);
7240
Daniel Veillardcda96922001-08-21 10:56:31 +00007241 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7242 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7243 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007244 (ctxt->value->floatval == 0.0))
7245 return;
7246
Owen Taylor3473f882001-02-23 17:55:21 +00007247 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007248 if (ctxt->value->floatval < 0) {
7249 if (ctxt->value->floatval < f - 0.5)
7250 ctxt->value->floatval = f - 1;
7251 else
7252 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007253 if (ctxt->value->floatval == 0)
7254 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007255 } else {
7256 if (ctxt->value->floatval < f + 0.5)
7257 ctxt->value->floatval = f;
7258 else
7259 ctxt->value->floatval = f + 1;
7260 }
Owen Taylor3473f882001-02-23 17:55:21 +00007261}
7262
7263/************************************************************************
7264 * *
7265 * The Parser *
7266 * *
7267 ************************************************************************/
7268
7269/*
William M. Brack08171912003-12-29 02:52:11 +00007270 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007271 * implementation.
7272 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007273static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007274static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007275static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007276static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007277static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7278 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007279
7280/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007281 * xmlXPathCurrentChar:
7282 * @ctxt: the XPath parser context
7283 * @cur: pointer to the beginning of the char
7284 * @len: pointer to the length of the char read
7285 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007286 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007287 * bytes in the input buffer.
7288 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007289 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007290 */
7291
7292static int
7293xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7294 unsigned char c;
7295 unsigned int val;
7296 const xmlChar *cur;
7297
7298 if (ctxt == NULL)
7299 return(0);
7300 cur = ctxt->cur;
7301
7302 /*
7303 * We are supposed to handle UTF8, check it's valid
7304 * From rfc2044: encoding of the Unicode values on UTF-8:
7305 *
7306 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7307 * 0000 0000-0000 007F 0xxxxxxx
7308 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7309 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7310 *
7311 * Check for the 0x110000 limit too
7312 */
7313 c = *cur;
7314 if (c & 0x80) {
7315 if ((cur[1] & 0xc0) != 0x80)
7316 goto encoding_error;
7317 if ((c & 0xe0) == 0xe0) {
7318
7319 if ((cur[2] & 0xc0) != 0x80)
7320 goto encoding_error;
7321 if ((c & 0xf0) == 0xf0) {
7322 if (((c & 0xf8) != 0xf0) ||
7323 ((cur[3] & 0xc0) != 0x80))
7324 goto encoding_error;
7325 /* 4-byte code */
7326 *len = 4;
7327 val = (cur[0] & 0x7) << 18;
7328 val |= (cur[1] & 0x3f) << 12;
7329 val |= (cur[2] & 0x3f) << 6;
7330 val |= cur[3] & 0x3f;
7331 } else {
7332 /* 3-byte code */
7333 *len = 3;
7334 val = (cur[0] & 0xf) << 12;
7335 val |= (cur[1] & 0x3f) << 6;
7336 val |= cur[2] & 0x3f;
7337 }
7338 } else {
7339 /* 2-byte code */
7340 *len = 2;
7341 val = (cur[0] & 0x1f) << 6;
7342 val |= cur[1] & 0x3f;
7343 }
7344 if (!IS_CHAR(val)) {
7345 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7346 }
7347 return(val);
7348 } else {
7349 /* 1-byte code */
7350 *len = 1;
7351 return((int) *cur);
7352 }
7353encoding_error:
7354 /*
William M. Brack08171912003-12-29 02:52:11 +00007355 * If we detect an UTF8 error that probably means that the
7356 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007357 * declaration header. Report the error and switch the encoding
7358 * to ISO-Latin-1 (if you don't like this policy, just declare the
7359 * encoding !)
7360 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007361 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007362 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007363}
7364
7365/**
Owen Taylor3473f882001-02-23 17:55:21 +00007366 * xmlXPathParseNCName:
7367 * @ctxt: the XPath Parser context
7368 *
7369 * parse an XML namespace non qualified name.
7370 *
7371 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7372 *
7373 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7374 * CombiningChar | Extender
7375 *
7376 * Returns the namespace name or NULL
7377 */
7378
7379xmlChar *
7380xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007381 const xmlChar *in;
7382 xmlChar *ret;
7383 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007384
Daniel Veillarda82b1822004-11-08 16:24:57 +00007385 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00007386 /*
7387 * Accelerator for simple ASCII names
7388 */
7389 in = ctxt->cur;
7390 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7391 ((*in >= 0x41) && (*in <= 0x5A)) ||
7392 (*in == '_')) {
7393 in++;
7394 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7395 ((*in >= 0x41) && (*in <= 0x5A)) ||
7396 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007397 (*in == '_') || (*in == '.') ||
7398 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007399 in++;
7400 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7401 (*in == '[') || (*in == ']') || (*in == ':') ||
7402 (*in == '@') || (*in == '*')) {
7403 count = in - ctxt->cur;
7404 if (count == 0)
7405 return(NULL);
7406 ret = xmlStrndup(ctxt->cur, count);
7407 ctxt->cur = in;
7408 return(ret);
7409 }
7410 }
7411 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007412}
7413
Daniel Veillard2156a562001-04-28 12:24:34 +00007414
Owen Taylor3473f882001-02-23 17:55:21 +00007415/**
7416 * xmlXPathParseQName:
7417 * @ctxt: the XPath Parser context
7418 * @prefix: a xmlChar **
7419 *
7420 * parse an XML qualified name
7421 *
7422 * [NS 5] QName ::= (Prefix ':')? LocalPart
7423 *
7424 * [NS 6] Prefix ::= NCName
7425 *
7426 * [NS 7] LocalPart ::= NCName
7427 *
7428 * Returns the function returns the local part, and prefix is updated
7429 * to get the Prefix if any.
7430 */
7431
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007432static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007433xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7434 xmlChar *ret = NULL;
7435
7436 *prefix = NULL;
7437 ret = xmlXPathParseNCName(ctxt);
7438 if (CUR == ':') {
7439 *prefix = ret;
7440 NEXT;
7441 ret = xmlXPathParseNCName(ctxt);
7442 }
7443 return(ret);
7444}
7445
7446/**
7447 * xmlXPathParseName:
7448 * @ctxt: the XPath Parser context
7449 *
7450 * parse an XML name
7451 *
7452 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7453 * CombiningChar | Extender
7454 *
7455 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7456 *
7457 * Returns the namespace name or NULL
7458 */
7459
7460xmlChar *
7461xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007462 const xmlChar *in;
7463 xmlChar *ret;
7464 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007465
Daniel Veillarda82b1822004-11-08 16:24:57 +00007466 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007467 /*
7468 * Accelerator for simple ASCII names
7469 */
7470 in = ctxt->cur;
7471 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7472 ((*in >= 0x41) && (*in <= 0x5A)) ||
7473 (*in == '_') || (*in == ':')) {
7474 in++;
7475 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7476 ((*in >= 0x41) && (*in <= 0x5A)) ||
7477 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007478 (*in == '_') || (*in == '-') ||
7479 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007480 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007481 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007482 count = in - ctxt->cur;
7483 ret = xmlStrndup(ctxt->cur, count);
7484 ctxt->cur = in;
7485 return(ret);
7486 }
7487 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007488 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007489}
7490
Daniel Veillard61d80a22001-04-27 17:13:01 +00007491static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007492xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007493 xmlChar buf[XML_MAX_NAMELEN + 5];
7494 int len = 0, l;
7495 int c;
7496
7497 /*
7498 * Handler for more complex cases
7499 */
7500 c = CUR_CHAR(l);
7501 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007502 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7503 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007504 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007505 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007506 return(NULL);
7507 }
7508
7509 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7510 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7511 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007512 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007513 (IS_COMBINING(c)) ||
7514 (IS_EXTENDER(c)))) {
7515 COPY_BUF(l,buf,len,c);
7516 NEXTL(l);
7517 c = CUR_CHAR(l);
7518 if (len >= XML_MAX_NAMELEN) {
7519 /*
7520 * Okay someone managed to make a huge name, so he's ready to pay
7521 * for the processing speed.
7522 */
7523 xmlChar *buffer;
7524 int max = len * 2;
7525
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007526 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007527 if (buffer == NULL) {
7528 XP_ERROR0(XPATH_MEMORY_ERROR);
7529 }
7530 memcpy(buffer, buf, len);
7531 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7532 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007533 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007534 (IS_COMBINING(c)) ||
7535 (IS_EXTENDER(c))) {
7536 if (len + 10 > max) {
7537 max *= 2;
7538 buffer = (xmlChar *) xmlRealloc(buffer,
7539 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007540 if (buffer == NULL) {
7541 XP_ERROR0(XPATH_MEMORY_ERROR);
7542 }
7543 }
7544 COPY_BUF(l,buffer,len,c);
7545 NEXTL(l);
7546 c = CUR_CHAR(l);
7547 }
7548 buffer[len] = 0;
7549 return(buffer);
7550 }
7551 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007552 if (len == 0)
7553 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007554 return(xmlStrndup(buf, len));
7555}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007556
7557#define MAX_FRAC 20
7558
William M. Brack372a4452004-02-17 13:09:23 +00007559/*
7560 * These are used as divisors for the fractional part of a number.
7561 * Since the table includes 1.0 (representing '0' fractional digits),
7562 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
7563 */
7564static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007565 1.0, 10.0, 100.0, 1000.0, 10000.0,
7566 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7567 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7568 100000000000000.0,
7569 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00007570 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00007571};
7572
Owen Taylor3473f882001-02-23 17:55:21 +00007573/**
7574 * xmlXPathStringEvalNumber:
7575 * @str: A string to scan
7576 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007577 * [30a] Float ::= Number ('e' Digits?)?
7578 *
Owen Taylor3473f882001-02-23 17:55:21 +00007579 * [30] Number ::= Digits ('.' Digits?)?
7580 * | '.' Digits
7581 * [31] Digits ::= [0-9]+
7582 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007583 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007584 * In complement of the Number expression, this function also handles
7585 * negative values : '-' Number.
7586 *
7587 * Returns the double value.
7588 */
7589double
7590xmlXPathStringEvalNumber(const xmlChar *str) {
7591 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007592 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007593 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007594 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007595 int exponent = 0;
7596 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007597#ifdef __GNUC__
7598 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007599 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007600#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007601 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007602 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007603 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7604 return(xmlXPathNAN);
7605 }
7606 if (*cur == '-') {
7607 isneg = 1;
7608 cur++;
7609 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007610
7611#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007612 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007613 * tmp/temp is a workaround against a gcc compiler bug
7614 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007615 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007616 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007617 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007618 ret = ret * 10;
7619 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007620 ok = 1;
7621 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007622 temp = (double) tmp;
7623 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007624 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007625#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007626 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007627 while ((*cur >= '0') && (*cur <= '9')) {
7628 ret = ret * 10 + (*cur - '0');
7629 ok = 1;
7630 cur++;
7631 }
7632#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007633
Owen Taylor3473f882001-02-23 17:55:21 +00007634 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007635 int v, frac = 0;
7636 double fraction = 0;
7637
Owen Taylor3473f882001-02-23 17:55:21 +00007638 cur++;
7639 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7640 return(xmlXPathNAN);
7641 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007642 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7643 v = (*cur - '0');
7644 fraction = fraction * 10 + v;
7645 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007646 cur++;
7647 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007648 fraction /= my_pow10[frac];
7649 ret = ret + fraction;
7650 while ((*cur >= '0') && (*cur <= '9'))
7651 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007652 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007653 if ((*cur == 'e') || (*cur == 'E')) {
7654 cur++;
7655 if (*cur == '-') {
7656 is_exponent_negative = 1;
7657 cur++;
William M. Brack99127052004-05-24 02:52:28 +00007658 } else if (*cur == '+') {
7659 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007660 }
7661 while ((*cur >= '0') && (*cur <= '9')) {
7662 exponent = exponent * 10 + (*cur - '0');
7663 cur++;
7664 }
7665 }
William M. Brack76e95df2003-10-18 16:20:14 +00007666 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007667 if (*cur != 0) return(xmlXPathNAN);
7668 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007669 if (is_exponent_negative) exponent = -exponent;
7670 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007671 return(ret);
7672}
7673
7674/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007675 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007676 * @ctxt: the XPath Parser context
7677 *
7678 * [30] Number ::= Digits ('.' Digits?)?
7679 * | '.' Digits
7680 * [31] Digits ::= [0-9]+
7681 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007682 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007683 *
7684 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007685static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007686xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7687{
Owen Taylor3473f882001-02-23 17:55:21 +00007688 double ret = 0.0;
7689 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007690 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007691 int exponent = 0;
7692 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007693#ifdef __GNUC__
7694 unsigned long tmp = 0;
7695 double temp;
7696#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007697
7698 CHECK_ERROR;
7699 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7700 XP_ERROR(XPATH_NUMBER_ERROR);
7701 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007702#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007703 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007704 * tmp/temp is a workaround against a gcc compiler bug
7705 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007706 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007707 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007708 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007709 ret = ret * 10;
7710 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007711 ok = 1;
7712 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007713 temp = (double) tmp;
7714 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007715 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007716#else
7717 ret = 0;
7718 while ((CUR >= '0') && (CUR <= '9')) {
7719 ret = ret * 10 + (CUR - '0');
7720 ok = 1;
7721 NEXT;
7722 }
7723#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007724 if (CUR == '.') {
7725 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007726 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7727 XP_ERROR(XPATH_NUMBER_ERROR);
7728 }
7729 while ((CUR >= '0') && (CUR <= '9')) {
7730 mult /= 10;
7731 ret = ret + (CUR - '0') * mult;
7732 NEXT;
7733 }
Owen Taylor3473f882001-02-23 17:55:21 +00007734 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007735 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007736 NEXT;
7737 if (CUR == '-') {
7738 is_exponent_negative = 1;
7739 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00007740 } else if (CUR == '+') {
7741 NEXT;
7742 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007743 while ((CUR >= '0') && (CUR <= '9')) {
7744 exponent = exponent * 10 + (CUR - '0');
7745 NEXT;
7746 }
7747 if (is_exponent_negative)
7748 exponent = -exponent;
7749 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007750 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007751 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007752 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007753}
7754
7755/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007756 * xmlXPathParseLiteral:
7757 * @ctxt: the XPath Parser context
7758 *
7759 * Parse a Literal
7760 *
7761 * [29] Literal ::= '"' [^"]* '"'
7762 * | "'" [^']* "'"
7763 *
7764 * Returns the value found or NULL in case of error
7765 */
7766static xmlChar *
7767xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7768 const xmlChar *q;
7769 xmlChar *ret = NULL;
7770
7771 if (CUR == '"') {
7772 NEXT;
7773 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007774 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007775 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007776 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007777 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7778 } else {
7779 ret = xmlStrndup(q, CUR_PTR - q);
7780 NEXT;
7781 }
7782 } else if (CUR == '\'') {
7783 NEXT;
7784 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007785 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007786 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007787 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007788 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7789 } else {
7790 ret = xmlStrndup(q, CUR_PTR - q);
7791 NEXT;
7792 }
7793 } else {
7794 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7795 }
7796 return(ret);
7797}
7798
7799/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007800 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007801 * @ctxt: the XPath Parser context
7802 *
7803 * Parse a Literal and push it on the stack.
7804 *
7805 * [29] Literal ::= '"' [^"]* '"'
7806 * | "'" [^']* "'"
7807 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007808 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007809 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007810static void
7811xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007812 const xmlChar *q;
7813 xmlChar *ret = NULL;
7814
7815 if (CUR == '"') {
7816 NEXT;
7817 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007818 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007819 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007820 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007821 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7822 } else {
7823 ret = xmlStrndup(q, CUR_PTR - q);
7824 NEXT;
7825 }
7826 } else if (CUR == '\'') {
7827 NEXT;
7828 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007829 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007830 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007831 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007832 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7833 } else {
7834 ret = xmlStrndup(q, CUR_PTR - q);
7835 NEXT;
7836 }
7837 } else {
7838 XP_ERROR(XPATH_START_LITERAL_ERROR);
7839 }
7840 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007841 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7842 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007843 xmlFree(ret);
7844}
7845
7846/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007847 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007848 * @ctxt: the XPath Parser context
7849 *
7850 * Parse a VariableReference, evaluate it and push it on the stack.
7851 *
7852 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00007853 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00007854 * of any of the types that are possible for the value of an expression,
7855 * and may also be of additional types not specified here.
7856 *
7857 * Early evaluation is possible since:
7858 * The variable bindings [...] used to evaluate a subexpression are
7859 * always the same as those used to evaluate the containing expression.
7860 *
7861 * [36] VariableReference ::= '$' QName
7862 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007863static void
7864xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007865 xmlChar *name;
7866 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007867
7868 SKIP_BLANKS;
7869 if (CUR != '$') {
7870 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7871 }
7872 NEXT;
7873 name = xmlXPathParseQName(ctxt, &prefix);
7874 if (name == NULL) {
7875 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7876 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007877 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007878 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7879 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007880 SKIP_BLANKS;
7881}
7882
7883/**
7884 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007885 * @name: a name string
7886 *
7887 * Is the name given a NodeType one.
7888 *
7889 * [38] NodeType ::= 'comment'
7890 * | 'text'
7891 * | 'processing-instruction'
7892 * | 'node'
7893 *
7894 * Returns 1 if true 0 otherwise
7895 */
7896int
7897xmlXPathIsNodeType(const xmlChar *name) {
7898 if (name == NULL)
7899 return(0);
7900
Daniel Veillard1971ee22002-01-31 20:29:19 +00007901 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007902 return(1);
7903 if (xmlStrEqual(name, BAD_CAST "text"))
7904 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007905 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007906 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007907 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007908 return(1);
7909 return(0);
7910}
7911
7912/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007913 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007914 * @ctxt: the XPath Parser context
7915 *
7916 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7917 * [17] Argument ::= Expr
7918 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007919 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007920 * pushed on the stack
7921 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007922static void
7923xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007924 xmlChar *name;
7925 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007926 int nbargs = 0;
7927
7928 name = xmlXPathParseQName(ctxt, &prefix);
7929 if (name == NULL) {
7930 XP_ERROR(XPATH_EXPR_ERROR);
7931 }
7932 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007933#ifdef DEBUG_EXPR
7934 if (prefix == NULL)
7935 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7936 name);
7937 else
7938 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7939 prefix, name);
7940#endif
7941
Owen Taylor3473f882001-02-23 17:55:21 +00007942 if (CUR != '(') {
7943 XP_ERROR(XPATH_EXPR_ERROR);
7944 }
7945 NEXT;
7946 SKIP_BLANKS;
7947
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007948 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007949 if (CUR != ')') {
7950 while (CUR != 0) {
7951 int op1 = ctxt->comp->last;
7952 ctxt->comp->last = -1;
7953 xmlXPathCompileExpr(ctxt);
7954 CHECK_ERROR;
7955 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7956 nbargs++;
7957 if (CUR == ')') break;
7958 if (CUR != ',') {
7959 XP_ERROR(XPATH_EXPR_ERROR);
7960 }
7961 NEXT;
7962 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007963 }
Owen Taylor3473f882001-02-23 17:55:21 +00007964 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007965 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7966 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007967 NEXT;
7968 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007969}
7970
7971/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007972 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007973 * @ctxt: the XPath Parser context
7974 *
7975 * [15] PrimaryExpr ::= VariableReference
7976 * | '(' Expr ')'
7977 * | Literal
7978 * | Number
7979 * | FunctionCall
7980 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007981 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007982 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007983static void
7984xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007985 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007986 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007987 else if (CUR == '(') {
7988 NEXT;
7989 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007990 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007991 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007992 if (CUR != ')') {
7993 XP_ERROR(XPATH_EXPR_ERROR);
7994 }
7995 NEXT;
7996 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00007997 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007998 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007999 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008000 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008001 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008002 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008003 }
8004 SKIP_BLANKS;
8005}
8006
8007/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008008 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008009 * @ctxt: the XPath Parser context
8010 *
8011 * [20] FilterExpr ::= PrimaryExpr
8012 * | FilterExpr Predicate
8013 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008014 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008015 * Square brackets are used to filter expressions in the same way that
8016 * they are used in location paths. It is an error if the expression to
8017 * be filtered does not evaluate to a node-set. The context node list
8018 * used for evaluating the expression in square brackets is the node-set
8019 * to be filtered listed in document order.
8020 */
8021
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008022static void
8023xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8024 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008025 CHECK_ERROR;
8026 SKIP_BLANKS;
8027
8028 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008029 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00008030 SKIP_BLANKS;
8031 }
8032
8033
8034}
8035
8036/**
8037 * xmlXPathScanName:
8038 * @ctxt: the XPath Parser context
8039 *
8040 * Trickery: parse an XML name but without consuming the input flow
8041 * Needed to avoid insanity in the parser state.
8042 *
8043 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8044 * CombiningChar | Extender
8045 *
8046 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8047 *
8048 * [6] Names ::= Name (S Name)*
8049 *
8050 * Returns the Name parsed or NULL
8051 */
8052
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008053static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00008054xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +00008055 int len = 0, l;
8056 int c;
Daniel Veillard03226812004-11-01 14:55:21 +00008057 const xmlChar *cur;
8058 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00008059
Daniel Veillard03226812004-11-01 14:55:21 +00008060 cur = ctxt->cur;
8061
8062 c = CUR_CHAR(l);
8063 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8064 (!IS_LETTER(c) && (c != '_') &&
8065 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008066 return(NULL);
8067 }
8068
Daniel Veillard03226812004-11-01 14:55:21 +00008069 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8070 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8071 (c == '.') || (c == '-') ||
8072 (c == '_') || (c == ':') ||
8073 (IS_COMBINING(c)) ||
8074 (IS_EXTENDER(c)))) {
8075 len += l;
8076 NEXTL(l);
8077 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +00008078 }
Daniel Veillard03226812004-11-01 14:55:21 +00008079 ret = xmlStrndup(cur, ctxt->cur - cur);
8080 ctxt->cur = cur;
8081 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00008082}
8083
8084/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008085 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008086 * @ctxt: the XPath Parser context
8087 *
8088 * [19] PathExpr ::= LocationPath
8089 * | FilterExpr
8090 * | FilterExpr '/' RelativeLocationPath
8091 * | FilterExpr '//' RelativeLocationPath
8092 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008093 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008094 * The / operator and // operators combine an arbitrary expression
8095 * and a relative location path. It is an error if the expression
8096 * does not evaluate to a node-set.
8097 * The / operator does composition in the same way as when / is
8098 * used in a location path. As in location paths, // is short for
8099 * /descendant-or-self::node()/.
8100 */
8101
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008102static void
8103xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008104 int lc = 1; /* Should we branch to LocationPath ? */
8105 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8106
8107 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008108 if ((CUR == '$') || (CUR == '(') ||
8109 (IS_ASCII_DIGIT(CUR)) ||
8110 (CUR == '\'') || (CUR == '"') ||
8111 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008112 lc = 0;
8113 } else if (CUR == '*') {
8114 /* relative or absolute location path */
8115 lc = 1;
8116 } else if (CUR == '/') {
8117 /* relative or absolute location path */
8118 lc = 1;
8119 } else if (CUR == '@') {
8120 /* relative abbreviated attribute location path */
8121 lc = 1;
8122 } else if (CUR == '.') {
8123 /* relative abbreviated attribute location path */
8124 lc = 1;
8125 } else {
8126 /*
8127 * Problem is finding if we have a name here whether it's:
8128 * - a nodetype
8129 * - a function call in which case it's followed by '('
8130 * - an axis in which case it's followed by ':'
8131 * - a element name
8132 * We do an a priori analysis here rather than having to
8133 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008134 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008135 * read/write/debug.
8136 */
8137 SKIP_BLANKS;
8138 name = xmlXPathScanName(ctxt);
8139 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8140#ifdef DEBUG_STEP
8141 xmlGenericError(xmlGenericErrorContext,
8142 "PathExpr: Axis\n");
8143#endif
8144 lc = 1;
8145 xmlFree(name);
8146 } else if (name != NULL) {
8147 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008148
8149
8150 while (NXT(len) != 0) {
8151 if (NXT(len) == '/') {
8152 /* element name */
8153#ifdef DEBUG_STEP
8154 xmlGenericError(xmlGenericErrorContext,
8155 "PathExpr: AbbrRelLocation\n");
8156#endif
8157 lc = 1;
8158 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008159 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008160 /* ignore blanks */
8161 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008162 } else if (NXT(len) == ':') {
8163#ifdef DEBUG_STEP
8164 xmlGenericError(xmlGenericErrorContext,
8165 "PathExpr: AbbrRelLocation\n");
8166#endif
8167 lc = 1;
8168 break;
8169 } else if ((NXT(len) == '(')) {
8170 /* Note Type or Function */
8171 if (xmlXPathIsNodeType(name)) {
8172#ifdef DEBUG_STEP
8173 xmlGenericError(xmlGenericErrorContext,
8174 "PathExpr: Type search\n");
8175#endif
8176 lc = 1;
8177 } else {
8178#ifdef DEBUG_STEP
8179 xmlGenericError(xmlGenericErrorContext,
8180 "PathExpr: function call\n");
8181#endif
8182 lc = 0;
8183 }
8184 break;
8185 } else if ((NXT(len) == '[')) {
8186 /* element name */
8187#ifdef DEBUG_STEP
8188 xmlGenericError(xmlGenericErrorContext,
8189 "PathExpr: AbbrRelLocation\n");
8190#endif
8191 lc = 1;
8192 break;
8193 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8194 (NXT(len) == '=')) {
8195 lc = 1;
8196 break;
8197 } else {
8198 lc = 1;
8199 break;
8200 }
8201 len++;
8202 }
8203 if (NXT(len) == 0) {
8204#ifdef DEBUG_STEP
8205 xmlGenericError(xmlGenericErrorContext,
8206 "PathExpr: AbbrRelLocation\n");
8207#endif
8208 /* element name */
8209 lc = 1;
8210 }
8211 xmlFree(name);
8212 } else {
William M. Brack08171912003-12-29 02:52:11 +00008213 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008214 XP_ERROR(XPATH_EXPR_ERROR);
8215 }
8216 }
8217
8218 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008219 if (CUR == '/') {
8220 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8221 } else {
8222 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008223 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008224 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008225 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008226 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008227 CHECK_ERROR;
8228 if ((CUR == '/') && (NXT(1) == '/')) {
8229 SKIP(2);
8230 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008231
8232 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8233 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8234 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8235
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008236 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008237 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008238 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008239 }
8240 }
8241 SKIP_BLANKS;
8242}
8243
8244/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008245 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008246 * @ctxt: the XPath Parser context
8247 *
8248 * [18] UnionExpr ::= PathExpr
8249 * | UnionExpr '|' PathExpr
8250 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008251 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008252 */
8253
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008254static void
8255xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8256 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008257 CHECK_ERROR;
8258 SKIP_BLANKS;
8259 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008260 int op1 = ctxt->comp->last;
8261 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008262
8263 NEXT;
8264 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008265 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008266
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008267 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8268
Owen Taylor3473f882001-02-23 17:55:21 +00008269 SKIP_BLANKS;
8270 }
Owen Taylor3473f882001-02-23 17:55:21 +00008271}
8272
8273/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008274 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008275 * @ctxt: the XPath Parser context
8276 *
8277 * [27] UnaryExpr ::= UnionExpr
8278 * | '-' UnaryExpr
8279 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008280 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008281 */
8282
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008283static void
8284xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008285 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008286 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008287
8288 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008289 while (CUR == '-') {
8290 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008291 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008292 NEXT;
8293 SKIP_BLANKS;
8294 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008295
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008296 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008297 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008298 if (found) {
8299 if (minus)
8300 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8301 else
8302 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008303 }
8304}
8305
8306/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008307 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008308 * @ctxt: the XPath Parser context
8309 *
8310 * [26] MultiplicativeExpr ::= UnaryExpr
8311 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8312 * | MultiplicativeExpr 'div' UnaryExpr
8313 * | MultiplicativeExpr 'mod' UnaryExpr
8314 * [34] MultiplyOperator ::= '*'
8315 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008316 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008317 */
8318
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008319static void
8320xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8321 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008322 CHECK_ERROR;
8323 SKIP_BLANKS;
8324 while ((CUR == '*') ||
8325 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8326 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8327 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008328 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008329
8330 if (CUR == '*') {
8331 op = 0;
8332 NEXT;
8333 } else if (CUR == 'd') {
8334 op = 1;
8335 SKIP(3);
8336 } else if (CUR == 'm') {
8337 op = 2;
8338 SKIP(3);
8339 }
8340 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008341 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008342 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008343 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008344 SKIP_BLANKS;
8345 }
8346}
8347
8348/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008349 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008350 * @ctxt: the XPath Parser context
8351 *
8352 * [25] AdditiveExpr ::= MultiplicativeExpr
8353 * | AdditiveExpr '+' MultiplicativeExpr
8354 * | AdditiveExpr '-' MultiplicativeExpr
8355 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008356 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008357 */
8358
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008359static void
8360xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008361
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008362 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008363 CHECK_ERROR;
8364 SKIP_BLANKS;
8365 while ((CUR == '+') || (CUR == '-')) {
8366 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008367 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008368
8369 if (CUR == '+') plus = 1;
8370 else plus = 0;
8371 NEXT;
8372 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008373 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008374 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008375 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008376 SKIP_BLANKS;
8377 }
8378}
8379
8380/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008381 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008382 * @ctxt: the XPath Parser context
8383 *
8384 * [24] RelationalExpr ::= AdditiveExpr
8385 * | RelationalExpr '<' AdditiveExpr
8386 * | RelationalExpr '>' AdditiveExpr
8387 * | RelationalExpr '<=' AdditiveExpr
8388 * | RelationalExpr '>=' AdditiveExpr
8389 *
8390 * A <= B > C is allowed ? Answer from James, yes with
8391 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8392 * which is basically what got implemented.
8393 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008394 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008395 * on the stack
8396 */
8397
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008398static void
8399xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8400 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008401 CHECK_ERROR;
8402 SKIP_BLANKS;
8403 while ((CUR == '<') ||
8404 (CUR == '>') ||
8405 ((CUR == '<') && (NXT(1) == '=')) ||
8406 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008407 int inf, strict;
8408 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008409
8410 if (CUR == '<') inf = 1;
8411 else inf = 0;
8412 if (NXT(1) == '=') strict = 0;
8413 else strict = 1;
8414 NEXT;
8415 if (!strict) NEXT;
8416 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008417 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008418 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008419 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008420 SKIP_BLANKS;
8421 }
8422}
8423
8424/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008425 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008426 * @ctxt: the XPath Parser context
8427 *
8428 * [23] EqualityExpr ::= RelationalExpr
8429 * | EqualityExpr '=' RelationalExpr
8430 * | EqualityExpr '!=' RelationalExpr
8431 *
8432 * A != B != C is allowed ? Answer from James, yes with
8433 * (RelationalExpr = RelationalExpr) = RelationalExpr
8434 * (RelationalExpr != RelationalExpr) != RelationalExpr
8435 * which is basically what got implemented.
8436 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008437 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008438 *
8439 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008440static void
8441xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8442 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008443 CHECK_ERROR;
8444 SKIP_BLANKS;
8445 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008446 int eq;
8447 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008448
8449 if (CUR == '=') eq = 1;
8450 else eq = 0;
8451 NEXT;
8452 if (!eq) NEXT;
8453 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008454 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008455 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008456 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008457 SKIP_BLANKS;
8458 }
8459}
8460
8461/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008462 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008463 * @ctxt: the XPath Parser context
8464 *
8465 * [22] AndExpr ::= EqualityExpr
8466 * | AndExpr 'and' EqualityExpr
8467 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008468 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008469 *
8470 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008471static void
8472xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8473 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008474 CHECK_ERROR;
8475 SKIP_BLANKS;
8476 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008477 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008478 SKIP(3);
8479 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008480 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008481 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008482 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008483 SKIP_BLANKS;
8484 }
8485}
8486
8487/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008488 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008489 * @ctxt: the XPath Parser context
8490 *
8491 * [14] Expr ::= OrExpr
8492 * [21] OrExpr ::= AndExpr
8493 * | OrExpr 'or' AndExpr
8494 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008495 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008496 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008497static void
8498xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8499 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008500 CHECK_ERROR;
8501 SKIP_BLANKS;
8502 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008503 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008504 SKIP(2);
8505 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008506 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008507 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008508 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8509 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008510 SKIP_BLANKS;
8511 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008512 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8513 /* more ops could be optimized too */
8514 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8515 }
Owen Taylor3473f882001-02-23 17:55:21 +00008516}
8517
8518/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008519 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008520 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008521 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008522 *
8523 * [8] Predicate ::= '[' PredicateExpr ']'
8524 * [9] PredicateExpr ::= Expr
8525 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008526 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008527 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008528static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008529xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008530 int op1 = ctxt->comp->last;
8531
8532 SKIP_BLANKS;
8533 if (CUR != '[') {
8534 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8535 }
8536 NEXT;
8537 SKIP_BLANKS;
8538
8539 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008540 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008541 CHECK_ERROR;
8542
8543 if (CUR != ']') {
8544 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8545 }
8546
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008547 if (filter)
8548 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8549 else
8550 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008551
8552 NEXT;
8553 SKIP_BLANKS;
8554}
8555
8556/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008557 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008558 * @ctxt: the XPath Parser context
8559 * @test: pointer to a xmlXPathTestVal
8560 * @type: pointer to a xmlXPathTypeVal
8561 * @prefix: placeholder for a possible name prefix
8562 *
8563 * [7] NodeTest ::= NameTest
8564 * | NodeType '(' ')'
8565 * | 'processing-instruction' '(' Literal ')'
8566 *
8567 * [37] NameTest ::= '*'
8568 * | NCName ':' '*'
8569 * | QName
8570 * [38] NodeType ::= 'comment'
8571 * | 'text'
8572 * | 'processing-instruction'
8573 * | 'node'
8574 *
William M. Brack08171912003-12-29 02:52:11 +00008575 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00008576 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008577static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008578xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8579 xmlXPathTypeVal *type, const xmlChar **prefix,
8580 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008581 int blanks;
8582
8583 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8584 STRANGE;
8585 return(NULL);
8586 }
William M. Brack78637da2003-07-31 14:47:38 +00008587 *type = (xmlXPathTypeVal) 0;
8588 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008589 *prefix = NULL;
8590 SKIP_BLANKS;
8591
8592 if ((name == NULL) && (CUR == '*')) {
8593 /*
8594 * All elements
8595 */
8596 NEXT;
8597 *test = NODE_TEST_ALL;
8598 return(NULL);
8599 }
8600
8601 if (name == NULL)
8602 name = xmlXPathParseNCName(ctxt);
8603 if (name == NULL) {
8604 XP_ERROR0(XPATH_EXPR_ERROR);
8605 }
8606
William M. Brack76e95df2003-10-18 16:20:14 +00008607 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008608 SKIP_BLANKS;
8609 if (CUR == '(') {
8610 NEXT;
8611 /*
8612 * NodeType or PI search
8613 */
8614 if (xmlStrEqual(name, BAD_CAST "comment"))
8615 *type = NODE_TYPE_COMMENT;
8616 else if (xmlStrEqual(name, BAD_CAST "node"))
8617 *type = NODE_TYPE_NODE;
8618 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8619 *type = NODE_TYPE_PI;
8620 else if (xmlStrEqual(name, BAD_CAST "text"))
8621 *type = NODE_TYPE_TEXT;
8622 else {
8623 if (name != NULL)
8624 xmlFree(name);
8625 XP_ERROR0(XPATH_EXPR_ERROR);
8626 }
8627
8628 *test = NODE_TEST_TYPE;
8629
8630 SKIP_BLANKS;
8631 if (*type == NODE_TYPE_PI) {
8632 /*
8633 * Specific case: search a PI by name.
8634 */
Owen Taylor3473f882001-02-23 17:55:21 +00008635 if (name != NULL)
8636 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008637 name = NULL;
8638 if (CUR != ')') {
8639 name = xmlXPathParseLiteral(ctxt);
8640 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008641 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008642 SKIP_BLANKS;
8643 }
Owen Taylor3473f882001-02-23 17:55:21 +00008644 }
8645 if (CUR != ')') {
8646 if (name != NULL)
8647 xmlFree(name);
8648 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8649 }
8650 NEXT;
8651 return(name);
8652 }
8653 *test = NODE_TEST_NAME;
8654 if ((!blanks) && (CUR == ':')) {
8655 NEXT;
8656
8657 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008658 * Since currently the parser context don't have a
8659 * namespace list associated:
8660 * The namespace name for this prefix can be computed
8661 * only at evaluation time. The compilation is done
8662 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008663 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008664#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008665 *prefix = xmlXPathNsLookup(ctxt->context, name);
8666 if (name != NULL)
8667 xmlFree(name);
8668 if (*prefix == NULL) {
8669 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8670 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008671#else
8672 *prefix = name;
8673#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008674
8675 if (CUR == '*') {
8676 /*
8677 * All elements
8678 */
8679 NEXT;
8680 *test = NODE_TEST_ALL;
8681 return(NULL);
8682 }
8683
8684 name = xmlXPathParseNCName(ctxt);
8685 if (name == NULL) {
8686 XP_ERROR0(XPATH_EXPR_ERROR);
8687 }
8688 }
8689 return(name);
8690}
8691
8692/**
8693 * xmlXPathIsAxisName:
8694 * @name: a preparsed name token
8695 *
8696 * [6] AxisName ::= 'ancestor'
8697 * | 'ancestor-or-self'
8698 * | 'attribute'
8699 * | 'child'
8700 * | 'descendant'
8701 * | 'descendant-or-self'
8702 * | 'following'
8703 * | 'following-sibling'
8704 * | 'namespace'
8705 * | 'parent'
8706 * | 'preceding'
8707 * | 'preceding-sibling'
8708 * | 'self'
8709 *
8710 * Returns the axis or 0
8711 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008712static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008713xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008714 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008715 switch (name[0]) {
8716 case 'a':
8717 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8718 ret = AXIS_ANCESTOR;
8719 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8720 ret = AXIS_ANCESTOR_OR_SELF;
8721 if (xmlStrEqual(name, BAD_CAST "attribute"))
8722 ret = AXIS_ATTRIBUTE;
8723 break;
8724 case 'c':
8725 if (xmlStrEqual(name, BAD_CAST "child"))
8726 ret = AXIS_CHILD;
8727 break;
8728 case 'd':
8729 if (xmlStrEqual(name, BAD_CAST "descendant"))
8730 ret = AXIS_DESCENDANT;
8731 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8732 ret = AXIS_DESCENDANT_OR_SELF;
8733 break;
8734 case 'f':
8735 if (xmlStrEqual(name, BAD_CAST "following"))
8736 ret = AXIS_FOLLOWING;
8737 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8738 ret = AXIS_FOLLOWING_SIBLING;
8739 break;
8740 case 'n':
8741 if (xmlStrEqual(name, BAD_CAST "namespace"))
8742 ret = AXIS_NAMESPACE;
8743 break;
8744 case 'p':
8745 if (xmlStrEqual(name, BAD_CAST "parent"))
8746 ret = AXIS_PARENT;
8747 if (xmlStrEqual(name, BAD_CAST "preceding"))
8748 ret = AXIS_PRECEDING;
8749 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8750 ret = AXIS_PRECEDING_SIBLING;
8751 break;
8752 case 's':
8753 if (xmlStrEqual(name, BAD_CAST "self"))
8754 ret = AXIS_SELF;
8755 break;
8756 }
8757 return(ret);
8758}
8759
8760/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008761 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008762 * @ctxt: the XPath Parser context
8763 *
8764 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8765 * | AbbreviatedStep
8766 *
8767 * [12] AbbreviatedStep ::= '.' | '..'
8768 *
8769 * [5] AxisSpecifier ::= AxisName '::'
8770 * | AbbreviatedAxisSpecifier
8771 *
8772 * [13] AbbreviatedAxisSpecifier ::= '@'?
8773 *
8774 * Modified for XPtr range support as:
8775 *
8776 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8777 * | AbbreviatedStep
8778 * | 'range-to' '(' Expr ')' Predicate*
8779 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008780 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008781 * A location step of . is short for self::node(). This is
8782 * particularly useful in conjunction with //. For example, the
8783 * location path .//para is short for
8784 * self::node()/descendant-or-self::node()/child::para
8785 * and so will select all para descendant elements of the context
8786 * node.
8787 * Similarly, a location step of .. is short for parent::node().
8788 * For example, ../title is short for parent::node()/child::title
8789 * and so will select the title children of the parent of the context
8790 * node.
8791 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008792static void
8793xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008794#ifdef LIBXML_XPTR_ENABLED
8795 int rangeto = 0;
8796 int op2 = -1;
8797#endif
8798
Owen Taylor3473f882001-02-23 17:55:21 +00008799 SKIP_BLANKS;
8800 if ((CUR == '.') && (NXT(1) == '.')) {
8801 SKIP(2);
8802 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008803 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8804 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008805 } else if (CUR == '.') {
8806 NEXT;
8807 SKIP_BLANKS;
8808 } else {
8809 xmlChar *name = NULL;
8810 const xmlChar *prefix = NULL;
8811 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008812 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008813 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008814 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008815
8816 /*
8817 * The modification needed for XPointer change to the production
8818 */
8819#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008820 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008821 name = xmlXPathParseNCName(ctxt);
8822 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008823 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008824 xmlFree(name);
8825 SKIP_BLANKS;
8826 if (CUR != '(') {
8827 XP_ERROR(XPATH_EXPR_ERROR);
8828 }
8829 NEXT;
8830 SKIP_BLANKS;
8831
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008832 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008833 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008834 CHECK_ERROR;
8835
8836 SKIP_BLANKS;
8837 if (CUR != ')') {
8838 XP_ERROR(XPATH_EXPR_ERROR);
8839 }
8840 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008841 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008842 goto eval_predicates;
8843 }
8844 }
8845#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008846 if (CUR == '*') {
8847 axis = AXIS_CHILD;
8848 } else {
8849 if (name == NULL)
8850 name = xmlXPathParseNCName(ctxt);
8851 if (name != NULL) {
8852 axis = xmlXPathIsAxisName(name);
8853 if (axis != 0) {
8854 SKIP_BLANKS;
8855 if ((CUR == ':') && (NXT(1) == ':')) {
8856 SKIP(2);
8857 xmlFree(name);
8858 name = NULL;
8859 } else {
8860 /* an element name can conflict with an axis one :-\ */
8861 axis = AXIS_CHILD;
8862 }
Owen Taylor3473f882001-02-23 17:55:21 +00008863 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008864 axis = AXIS_CHILD;
8865 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008866 } else if (CUR == '@') {
8867 NEXT;
8868 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008869 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008870 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008871 }
Owen Taylor3473f882001-02-23 17:55:21 +00008872 }
8873
8874 CHECK_ERROR;
8875
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008876 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008877 if (test == 0)
8878 return;
8879
8880#ifdef DEBUG_STEP
8881 xmlGenericError(xmlGenericErrorContext,
8882 "Basis : computing new set\n");
8883#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008884
Owen Taylor3473f882001-02-23 17:55:21 +00008885#ifdef DEBUG_STEP
8886 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008887 if (ctxt->value == NULL)
8888 xmlGenericError(xmlGenericErrorContext, "no value\n");
8889 else if (ctxt->value->nodesetval == NULL)
8890 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8891 else
8892 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008893#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008894
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008895#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008896eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008897#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008898 op1 = ctxt->comp->last;
8899 ctxt->comp->last = -1;
8900
Owen Taylor3473f882001-02-23 17:55:21 +00008901 SKIP_BLANKS;
8902 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008903 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008904 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008905
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008906#ifdef LIBXML_XPTR_ENABLED
8907 if (rangeto) {
8908 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8909 } else
8910#endif
8911 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8912 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008913
Owen Taylor3473f882001-02-23 17:55:21 +00008914 }
8915#ifdef DEBUG_STEP
8916 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008917 if (ctxt->value == NULL)
8918 xmlGenericError(xmlGenericErrorContext, "no value\n");
8919 else if (ctxt->value->nodesetval == NULL)
8920 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8921 else
8922 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8923 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008924#endif
8925}
8926
8927/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008928 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008929 * @ctxt: the XPath Parser context
8930 *
8931 * [3] RelativeLocationPath ::= Step
8932 * | RelativeLocationPath '/' Step
8933 * | AbbreviatedRelativeLocationPath
8934 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8935 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008936 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008937 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008938static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008939xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008940(xmlXPathParserContextPtr ctxt) {
8941 SKIP_BLANKS;
8942 if ((CUR == '/') && (NXT(1) == '/')) {
8943 SKIP(2);
8944 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008945 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8946 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008947 } else if (CUR == '/') {
8948 NEXT;
8949 SKIP_BLANKS;
8950 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008951 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008952 SKIP_BLANKS;
8953 while (CUR == '/') {
8954 if ((CUR == '/') && (NXT(1) == '/')) {
8955 SKIP(2);
8956 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008957 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008958 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008959 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008960 } else if (CUR == '/') {
8961 NEXT;
8962 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008963 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008964 }
8965 SKIP_BLANKS;
8966 }
8967}
8968
8969/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008970 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008971 * @ctxt: the XPath Parser context
8972 *
8973 * [1] LocationPath ::= RelativeLocationPath
8974 * | AbsoluteLocationPath
8975 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8976 * | AbbreviatedAbsoluteLocationPath
8977 * [10] AbbreviatedAbsoluteLocationPath ::=
8978 * '//' RelativeLocationPath
8979 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008980 * Compile a location path
8981 *
Owen Taylor3473f882001-02-23 17:55:21 +00008982 * // is short for /descendant-or-self::node()/. For example,
8983 * //para is short for /descendant-or-self::node()/child::para and
8984 * so will select any para element in the document (even a para element
8985 * that is a document element will be selected by //para since the
8986 * document element node is a child of the root node); div//para is
8987 * short for div/descendant-or-self::node()/child::para and so will
8988 * select all para descendants of div children.
8989 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008990static void
8991xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008992 SKIP_BLANKS;
8993 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008994 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008995 } else {
8996 while (CUR == '/') {
8997 if ((CUR == '/') && (NXT(1) == '/')) {
8998 SKIP(2);
8999 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009000 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9001 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009002 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009003 } else if (CUR == '/') {
9004 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00009005 SKIP_BLANKS;
9006 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +00009007 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00009008 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009009 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009010 }
9011 }
9012 }
9013}
9014
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009015/************************************************************************
9016 * *
9017 * XPath precompiled expression evaluation *
9018 * *
9019 ************************************************************************/
9020
Daniel Veillardf06307e2001-07-03 10:35:50 +00009021static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009022xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
9023
9024/**
9025 * xmlXPathNodeCollectAndTest:
9026 * @ctxt: the XPath Parser context
9027 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009028 * @first: pointer to the first element in document order
9029 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009030 *
9031 * This is the function implementing a step: based on the current list
9032 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009033 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009034 *
9035 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00009036 *
William M. Brack08171912003-12-29 02:52:11 +00009037 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009038 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009039static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009040xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009041 xmlXPathStepOpPtr op,
9042 xmlNodePtr * first, xmlNodePtr * last)
9043{
William M. Brack78637da2003-07-31 14:47:38 +00009044 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9045 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9046 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009047 const xmlChar *prefix = op->value4;
9048 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009049 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009050
9051#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009052 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009053#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009054 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009055 xmlNodeSetPtr ret, list;
9056 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009057 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00009058 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009059 xmlNodePtr cur = NULL;
9060 xmlXPathObjectPtr obj;
9061 xmlNodeSetPtr nodelist;
9062 xmlNodePtr tmp;
9063
Daniel Veillardf06307e2001-07-03 10:35:50 +00009064 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009065 obj = valuePop(ctxt);
9066 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009067 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009068 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009069 URI = xmlXPathNsLookup(ctxt->context, prefix);
9070 if (URI == NULL)
9071 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00009072 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009073#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009074 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009075#endif
9076 switch (axis) {
9077 case AXIS_ANCESTOR:
9078#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009079 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009080#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009081 first = NULL;
9082 next = xmlXPathNextAncestor;
9083 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009084 case AXIS_ANCESTOR_OR_SELF:
9085#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009086 xmlGenericError(xmlGenericErrorContext,
9087 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009088#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009089 first = NULL;
9090 next = xmlXPathNextAncestorOrSelf;
9091 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009092 case AXIS_ATTRIBUTE:
9093#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009094 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009095#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009096 first = NULL;
9097 last = NULL;
9098 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009099 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009100 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009101 case AXIS_CHILD:
9102#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009103 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009104#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009105 last = NULL;
9106 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009107 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009108 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009109 case AXIS_DESCENDANT:
9110#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009111 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009112#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009113 last = NULL;
9114 next = xmlXPathNextDescendant;
9115 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009116 case AXIS_DESCENDANT_OR_SELF:
9117#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009118 xmlGenericError(xmlGenericErrorContext,
9119 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009120#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009121 last = NULL;
9122 next = xmlXPathNextDescendantOrSelf;
9123 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009124 case AXIS_FOLLOWING:
9125#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009126 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009127#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009128 last = NULL;
9129 next = xmlXPathNextFollowing;
9130 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009131 case AXIS_FOLLOWING_SIBLING:
9132#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009133 xmlGenericError(xmlGenericErrorContext,
9134 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009135#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009136 last = NULL;
9137 next = xmlXPathNextFollowingSibling;
9138 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009139 case AXIS_NAMESPACE:
9140#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009141 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009142#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009143 first = NULL;
9144 last = NULL;
9145 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009146 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009147 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009148 case AXIS_PARENT:
9149#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009150 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009151#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009152 first = NULL;
9153 next = xmlXPathNextParent;
9154 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009155 case AXIS_PRECEDING:
9156#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009157 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009158#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009159 first = NULL;
9160 next = xmlXPathNextPrecedingInternal;
9161 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009162 case AXIS_PRECEDING_SIBLING:
9163#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009164 xmlGenericError(xmlGenericErrorContext,
9165 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009166#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009167 first = NULL;
9168 next = xmlXPathNextPrecedingSibling;
9169 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009170 case AXIS_SELF:
9171#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009172 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009173#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009174 first = NULL;
9175 last = NULL;
9176 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009177 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009178 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009179 }
9180 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009181 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009182
9183 nodelist = obj->nodesetval;
9184 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009185 xmlXPathFreeObject(obj);
9186 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9187 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009188 }
9189 addNode = xmlXPathNodeSetAddUnique;
9190 ret = NULL;
9191#ifdef DEBUG_STEP
9192 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009193 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009194 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009195 case NODE_TEST_NONE:
9196 xmlGenericError(xmlGenericErrorContext,
9197 " searching for none !!!\n");
9198 break;
9199 case NODE_TEST_TYPE:
9200 xmlGenericError(xmlGenericErrorContext,
9201 " searching for type %d\n", type);
9202 break;
9203 case NODE_TEST_PI:
9204 xmlGenericError(xmlGenericErrorContext,
9205 " searching for PI !!!\n");
9206 break;
9207 case NODE_TEST_ALL:
9208 xmlGenericError(xmlGenericErrorContext,
9209 " searching for *\n");
9210 break;
9211 case NODE_TEST_NS:
9212 xmlGenericError(xmlGenericErrorContext,
9213 " searching for namespace %s\n",
9214 prefix);
9215 break;
9216 case NODE_TEST_NAME:
9217 xmlGenericError(xmlGenericErrorContext,
9218 " searching for name %s\n", name);
9219 if (prefix != NULL)
9220 xmlGenericError(xmlGenericErrorContext,
9221 " with namespace %s\n", prefix);
9222 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009223 }
9224 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9225#endif
9226 /*
9227 * 2.3 Node Tests
9228 * - For the attribute axis, the principal node type is attribute.
9229 * - For the namespace axis, the principal node type is namespace.
9230 * - For other axes, the principal node type is element.
9231 *
9232 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009233 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009234 * select all element children of the context node
9235 */
9236 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009237 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009238 ctxt->context->node = nodelist->nodeTab[i];
9239
Daniel Veillardf06307e2001-07-03 10:35:50 +00009240 cur = NULL;
9241 list = xmlXPathNodeSetCreate(NULL);
9242 do {
9243 cur = next(ctxt, cur);
9244 if (cur == NULL)
9245 break;
9246 if ((first != NULL) && (*first == cur))
9247 break;
9248 if (((t % 256) == 0) &&
9249 (first != NULL) && (*first != NULL) &&
9250 (xmlXPathCmpNodes(*first, cur) >= 0))
9251 break;
9252 if ((last != NULL) && (*last == cur))
9253 break;
9254 if (((t % 256) == 0) &&
9255 (last != NULL) && (*last != NULL) &&
9256 (xmlXPathCmpNodes(cur, *last) >= 0))
9257 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009258 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009259#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009260 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9261#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009262 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009263 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009264 ctxt->context->node = tmp;
9265 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009266 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009267 if ((cur->type == type) ||
9268 ((type == NODE_TYPE_NODE) &&
9269 ((cur->type == XML_DOCUMENT_NODE) ||
9270 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9271 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009272 (cur->type == XML_NAMESPACE_DECL) ||
9273 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009274 (cur->type == XML_PI_NODE) ||
9275 (cur->type == XML_COMMENT_NODE) ||
9276 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009277 (cur->type == XML_TEXT_NODE))) ||
9278 ((type == NODE_TYPE_TEXT) &&
9279 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009280#ifdef DEBUG_STEP
9281 n++;
9282#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009283 addNode(list, cur);
9284 }
9285 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009286 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009287 if (cur->type == XML_PI_NODE) {
9288 if ((name != NULL) &&
9289 (!xmlStrEqual(name, cur->name)))
9290 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009291#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009292 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009293#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009294 addNode(list, cur);
9295 }
9296 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009297 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009298 if (axis == AXIS_ATTRIBUTE) {
9299 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009300#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009301 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009302#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009303 addNode(list, cur);
9304 }
9305 } else if (axis == AXIS_NAMESPACE) {
9306 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009307#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009308 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009309#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009310 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9311 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009312 }
9313 } else {
9314 if (cur->type == XML_ELEMENT_NODE) {
9315 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009316#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009317 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009318#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009319 addNode(list, cur);
9320 } else if ((cur->ns != NULL) &&
9321 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009322#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009323 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009324#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009325 addNode(list, cur);
9326 }
9327 }
9328 }
9329 break;
9330 case NODE_TEST_NS:{
9331 TODO;
9332 break;
9333 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009334 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009335 switch (cur->type) {
9336 case XML_ELEMENT_NODE:
9337 if (xmlStrEqual(name, cur->name)) {
9338 if (prefix == NULL) {
9339 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009340#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009341 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009342#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009343 addNode(list, cur);
9344 }
9345 } else {
9346 if ((cur->ns != NULL) &&
9347 (xmlStrEqual(URI,
9348 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009349#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009350 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009351#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009352 addNode(list, cur);
9353 }
9354 }
9355 }
9356 break;
9357 case XML_ATTRIBUTE_NODE:{
9358 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009359
Daniel Veillardf06307e2001-07-03 10:35:50 +00009360 if (xmlStrEqual(name, attr->name)) {
9361 if (prefix == NULL) {
9362 if ((attr->ns == NULL) ||
9363 (attr->ns->prefix == NULL)) {
9364#ifdef DEBUG_STEP
9365 n++;
9366#endif
9367 addNode(list,
9368 (xmlNodePtr) attr);
9369 }
9370 } else {
9371 if ((attr->ns != NULL) &&
9372 (xmlStrEqual(URI,
9373 attr->ns->
9374 href))) {
9375#ifdef DEBUG_STEP
9376 n++;
9377#endif
9378 addNode(list,
9379 (xmlNodePtr) attr);
9380 }
9381 }
9382 }
9383 break;
9384 }
9385 case XML_NAMESPACE_DECL:
9386 if (cur->type == XML_NAMESPACE_DECL) {
9387 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009388
Daniel Veillardf06307e2001-07-03 10:35:50 +00009389 if ((ns->prefix != NULL) && (name != NULL)
9390 && (xmlStrEqual(ns->prefix, name))) {
9391#ifdef DEBUG_STEP
9392 n++;
9393#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009394 xmlXPathNodeSetAddNs(list,
9395 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009396 }
9397 }
9398 break;
9399 default:
9400 break;
9401 }
9402 break;
9403 break;
9404 }
9405 } while (cur != NULL);
9406
9407 /*
9408 * If there is some predicate filtering do it now
9409 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009410 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009411 xmlXPathObjectPtr obj2;
9412
9413 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9414 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9415 CHECK_TYPE0(XPATH_NODESET);
9416 obj2 = valuePop(ctxt);
9417 list = obj2->nodesetval;
9418 obj2->nodesetval = NULL;
9419 xmlXPathFreeObject(obj2);
9420 }
9421 if (ret == NULL) {
9422 ret = list;
9423 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009424 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009425 xmlXPathFreeNodeSet(list);
9426 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009427 }
9428 ctxt->context->node = tmp;
9429#ifdef DEBUG_STEP
9430 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009431 "\nExamined %d nodes, found %d nodes at that step\n",
9432 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009433#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009434 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009435 if ((obj->boolval) && (obj->user != NULL)) {
9436 ctxt->value->boolval = 1;
9437 ctxt->value->user = obj->user;
9438 obj->user = NULL;
9439 obj->boolval = 0;
9440 }
9441 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009442 return(t);
9443}
9444
9445/**
9446 * xmlXPathNodeCollectAndTestNth:
9447 * @ctxt: the XPath Parser context
9448 * @op: the XPath precompiled step operation
9449 * @indx: the index to collect
9450 * @first: pointer to the first element in document order
9451 * @last: pointer to the last element in document order
9452 *
9453 * This is the function implementing a step: based on the current list
9454 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009455 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009456 *
9457 * Pushes the new NodeSet resulting from the search.
9458 * Returns the number of node traversed
9459 */
9460static int
9461xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9462 xmlXPathStepOpPtr op, int indx,
9463 xmlNodePtr * first, xmlNodePtr * last)
9464{
William M. Brack78637da2003-07-31 14:47:38 +00009465 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9466 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9467 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009468 const xmlChar *prefix = op->value4;
9469 const xmlChar *name = op->value5;
9470 const xmlChar *URI = NULL;
9471 int n = 0, t = 0;
9472
9473 int i;
9474 xmlNodeSetPtr list;
9475 xmlXPathTraversalFunction next = NULL;
9476 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9477 xmlNodePtr cur = NULL;
9478 xmlXPathObjectPtr obj;
9479 xmlNodeSetPtr nodelist;
9480 xmlNodePtr tmp;
9481
9482 CHECK_TYPE0(XPATH_NODESET);
9483 obj = valuePop(ctxt);
9484 addNode = xmlXPathNodeSetAdd;
9485 if (prefix != NULL) {
9486 URI = xmlXPathNsLookup(ctxt->context, prefix);
9487 if (URI == NULL)
9488 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9489 }
9490#ifdef DEBUG_STEP_NTH
9491 xmlGenericError(xmlGenericErrorContext, "new step : ");
9492 if (first != NULL) {
9493 if (*first != NULL)
9494 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9495 (*first)->name);
9496 else
9497 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9498 }
9499 if (last != NULL) {
9500 if (*last != NULL)
9501 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9502 (*last)->name);
9503 else
9504 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9505 }
9506#endif
9507 switch (axis) {
9508 case AXIS_ANCESTOR:
9509#ifdef DEBUG_STEP_NTH
9510 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9511#endif
9512 first = NULL;
9513 next = xmlXPathNextAncestor;
9514 break;
9515 case AXIS_ANCESTOR_OR_SELF:
9516#ifdef DEBUG_STEP_NTH
9517 xmlGenericError(xmlGenericErrorContext,
9518 "axis 'ancestors-or-self' ");
9519#endif
9520 first = NULL;
9521 next = xmlXPathNextAncestorOrSelf;
9522 break;
9523 case AXIS_ATTRIBUTE:
9524#ifdef DEBUG_STEP_NTH
9525 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9526#endif
9527 first = NULL;
9528 last = NULL;
9529 next = xmlXPathNextAttribute;
9530 break;
9531 case AXIS_CHILD:
9532#ifdef DEBUG_STEP_NTH
9533 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9534#endif
9535 last = NULL;
9536 next = xmlXPathNextChild;
9537 break;
9538 case AXIS_DESCENDANT:
9539#ifdef DEBUG_STEP_NTH
9540 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9541#endif
9542 last = NULL;
9543 next = xmlXPathNextDescendant;
9544 break;
9545 case AXIS_DESCENDANT_OR_SELF:
9546#ifdef DEBUG_STEP_NTH
9547 xmlGenericError(xmlGenericErrorContext,
9548 "axis 'descendant-or-self' ");
9549#endif
9550 last = NULL;
9551 next = xmlXPathNextDescendantOrSelf;
9552 break;
9553 case AXIS_FOLLOWING:
9554#ifdef DEBUG_STEP_NTH
9555 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9556#endif
9557 last = NULL;
9558 next = xmlXPathNextFollowing;
9559 break;
9560 case AXIS_FOLLOWING_SIBLING:
9561#ifdef DEBUG_STEP_NTH
9562 xmlGenericError(xmlGenericErrorContext,
9563 "axis 'following-siblings' ");
9564#endif
9565 last = NULL;
9566 next = xmlXPathNextFollowingSibling;
9567 break;
9568 case AXIS_NAMESPACE:
9569#ifdef DEBUG_STEP_NTH
9570 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9571#endif
9572 last = NULL;
9573 first = NULL;
9574 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9575 break;
9576 case AXIS_PARENT:
9577#ifdef DEBUG_STEP_NTH
9578 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9579#endif
9580 first = NULL;
9581 next = xmlXPathNextParent;
9582 break;
9583 case AXIS_PRECEDING:
9584#ifdef DEBUG_STEP_NTH
9585 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9586#endif
9587 first = NULL;
9588 next = xmlXPathNextPrecedingInternal;
9589 break;
9590 case AXIS_PRECEDING_SIBLING:
9591#ifdef DEBUG_STEP_NTH
9592 xmlGenericError(xmlGenericErrorContext,
9593 "axis 'preceding-sibling' ");
9594#endif
9595 first = NULL;
9596 next = xmlXPathNextPrecedingSibling;
9597 break;
9598 case AXIS_SELF:
9599#ifdef DEBUG_STEP_NTH
9600 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9601#endif
9602 first = NULL;
9603 last = NULL;
9604 next = xmlXPathNextSelf;
9605 break;
9606 }
9607 if (next == NULL)
9608 return(0);
9609
9610 nodelist = obj->nodesetval;
9611 if (nodelist == NULL) {
9612 xmlXPathFreeObject(obj);
9613 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9614 return(0);
9615 }
9616 addNode = xmlXPathNodeSetAddUnique;
9617#ifdef DEBUG_STEP_NTH
9618 xmlGenericError(xmlGenericErrorContext,
9619 " context contains %d nodes\n", nodelist->nodeNr);
9620 switch (test) {
9621 case NODE_TEST_NONE:
9622 xmlGenericError(xmlGenericErrorContext,
9623 " searching for none !!!\n");
9624 break;
9625 case NODE_TEST_TYPE:
9626 xmlGenericError(xmlGenericErrorContext,
9627 " searching for type %d\n", type);
9628 break;
9629 case NODE_TEST_PI:
9630 xmlGenericError(xmlGenericErrorContext,
9631 " searching for PI !!!\n");
9632 break;
9633 case NODE_TEST_ALL:
9634 xmlGenericError(xmlGenericErrorContext,
9635 " searching for *\n");
9636 break;
9637 case NODE_TEST_NS:
9638 xmlGenericError(xmlGenericErrorContext,
9639 " searching for namespace %s\n",
9640 prefix);
9641 break;
9642 case NODE_TEST_NAME:
9643 xmlGenericError(xmlGenericErrorContext,
9644 " searching for name %s\n", name);
9645 if (prefix != NULL)
9646 xmlGenericError(xmlGenericErrorContext,
9647 " with namespace %s\n", prefix);
9648 break;
9649 }
9650 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9651#endif
9652 /*
9653 * 2.3 Node Tests
9654 * - For the attribute axis, the principal node type is attribute.
9655 * - For the namespace axis, the principal node type is namespace.
9656 * - For other axes, the principal node type is element.
9657 *
9658 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009659 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009660 * select all element children of the context node
9661 */
9662 tmp = ctxt->context->node;
9663 list = xmlXPathNodeSetCreate(NULL);
9664 for (i = 0; i < nodelist->nodeNr; i++) {
9665 ctxt->context->node = nodelist->nodeTab[i];
9666
9667 cur = NULL;
9668 n = 0;
9669 do {
9670 cur = next(ctxt, cur);
9671 if (cur == NULL)
9672 break;
9673 if ((first != NULL) && (*first == cur))
9674 break;
9675 if (((t % 256) == 0) &&
9676 (first != NULL) && (*first != NULL) &&
9677 (xmlXPathCmpNodes(*first, cur) >= 0))
9678 break;
9679 if ((last != NULL) && (*last == cur))
9680 break;
9681 if (((t % 256) == 0) &&
9682 (last != NULL) && (*last != NULL) &&
9683 (xmlXPathCmpNodes(cur, *last) >= 0))
9684 break;
9685 t++;
9686 switch (test) {
9687 case NODE_TEST_NONE:
9688 ctxt->context->node = tmp;
9689 STRANGE return(0);
9690 case NODE_TEST_TYPE:
9691 if ((cur->type == type) ||
9692 ((type == NODE_TYPE_NODE) &&
9693 ((cur->type == XML_DOCUMENT_NODE) ||
9694 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9695 (cur->type == XML_ELEMENT_NODE) ||
9696 (cur->type == XML_PI_NODE) ||
9697 (cur->type == XML_COMMENT_NODE) ||
9698 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009699 (cur->type == XML_TEXT_NODE))) ||
9700 ((type == NODE_TYPE_TEXT) &&
9701 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009702 n++;
9703 if (n == indx)
9704 addNode(list, cur);
9705 }
9706 break;
9707 case NODE_TEST_PI:
9708 if (cur->type == XML_PI_NODE) {
9709 if ((name != NULL) &&
9710 (!xmlStrEqual(name, cur->name)))
9711 break;
9712 n++;
9713 if (n == indx)
9714 addNode(list, cur);
9715 }
9716 break;
9717 case NODE_TEST_ALL:
9718 if (axis == AXIS_ATTRIBUTE) {
9719 if (cur->type == XML_ATTRIBUTE_NODE) {
9720 n++;
9721 if (n == indx)
9722 addNode(list, cur);
9723 }
9724 } else if (axis == AXIS_NAMESPACE) {
9725 if (cur->type == XML_NAMESPACE_DECL) {
9726 n++;
9727 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009728 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9729 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009730 }
9731 } else {
9732 if (cur->type == XML_ELEMENT_NODE) {
9733 if (prefix == NULL) {
9734 n++;
9735 if (n == indx)
9736 addNode(list, cur);
9737 } else if ((cur->ns != NULL) &&
9738 (xmlStrEqual(URI, cur->ns->href))) {
9739 n++;
9740 if (n == indx)
9741 addNode(list, cur);
9742 }
9743 }
9744 }
9745 break;
9746 case NODE_TEST_NS:{
9747 TODO;
9748 break;
9749 }
9750 case NODE_TEST_NAME:
9751 switch (cur->type) {
9752 case XML_ELEMENT_NODE:
9753 if (xmlStrEqual(name, cur->name)) {
9754 if (prefix == NULL) {
9755 if (cur->ns == NULL) {
9756 n++;
9757 if (n == indx)
9758 addNode(list, cur);
9759 }
9760 } else {
9761 if ((cur->ns != NULL) &&
9762 (xmlStrEqual(URI,
9763 cur->ns->href))) {
9764 n++;
9765 if (n == indx)
9766 addNode(list, cur);
9767 }
9768 }
9769 }
9770 break;
9771 case XML_ATTRIBUTE_NODE:{
9772 xmlAttrPtr attr = (xmlAttrPtr) cur;
9773
9774 if (xmlStrEqual(name, attr->name)) {
9775 if (prefix == NULL) {
9776 if ((attr->ns == NULL) ||
9777 (attr->ns->prefix == NULL)) {
9778 n++;
9779 if (n == indx)
9780 addNode(list, cur);
9781 }
9782 } else {
9783 if ((attr->ns != NULL) &&
9784 (xmlStrEqual(URI,
9785 attr->ns->
9786 href))) {
9787 n++;
9788 if (n == indx)
9789 addNode(list, cur);
9790 }
9791 }
9792 }
9793 break;
9794 }
9795 case XML_NAMESPACE_DECL:
9796 if (cur->type == XML_NAMESPACE_DECL) {
9797 xmlNsPtr ns = (xmlNsPtr) cur;
9798
9799 if ((ns->prefix != NULL) && (name != NULL)
9800 && (xmlStrEqual(ns->prefix, name))) {
9801 n++;
9802 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009803 xmlXPathNodeSetAddNs(list,
9804 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009805 }
9806 }
9807 break;
9808 default:
9809 break;
9810 }
9811 break;
9812 break;
9813 }
9814 } while (n < indx);
9815 }
9816 ctxt->context->node = tmp;
9817#ifdef DEBUG_STEP_NTH
9818 xmlGenericError(xmlGenericErrorContext,
9819 "\nExamined %d nodes, found %d nodes at that step\n",
9820 t, list->nodeNr);
9821#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009822 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009823 if ((obj->boolval) && (obj->user != NULL)) {
9824 ctxt->value->boolval = 1;
9825 ctxt->value->user = obj->user;
9826 obj->user = NULL;
9827 obj->boolval = 0;
9828 }
9829 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009830 return(t);
9831}
9832
9833/**
9834 * xmlXPathCompOpEvalFirst:
9835 * @ctxt: the XPath parser context with the compiled expression
9836 * @op: an XPath compiled operation
9837 * @first: the first elem found so far
9838 *
9839 * Evaluate the Precompiled XPath operation searching only the first
9840 * element in document order
9841 *
9842 * Returns the number of examined objects.
9843 */
9844static int
9845xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9846 xmlXPathStepOpPtr op, xmlNodePtr * first)
9847{
9848 int total = 0, cur;
9849 xmlXPathCompExprPtr comp;
9850 xmlXPathObjectPtr arg1, arg2;
9851
Daniel Veillard556c6682001-10-06 09:59:51 +00009852 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009853 comp = ctxt->comp;
9854 switch (op->op) {
9855 case XPATH_OP_END:
9856 return (0);
9857 case XPATH_OP_UNION:
9858 total =
9859 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9860 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009861 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009862 if ((ctxt->value != NULL)
9863 && (ctxt->value->type == XPATH_NODESET)
9864 && (ctxt->value->nodesetval != NULL)
9865 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9866 /*
9867 * limit tree traversing to first node in the result
9868 */
9869 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9870 *first = ctxt->value->nodesetval->nodeTab[0];
9871 }
9872 cur =
9873 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9874 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009875 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009876 CHECK_TYPE0(XPATH_NODESET);
9877 arg2 = valuePop(ctxt);
9878
9879 CHECK_TYPE0(XPATH_NODESET);
9880 arg1 = valuePop(ctxt);
9881
9882 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9883 arg2->nodesetval);
9884 valuePush(ctxt, arg1);
9885 xmlXPathFreeObject(arg2);
9886 /* optimizer */
9887 if (total > cur)
9888 xmlXPathCompSwap(op);
9889 return (total + cur);
9890 case XPATH_OP_ROOT:
9891 xmlXPathRoot(ctxt);
9892 return (0);
9893 case XPATH_OP_NODE:
9894 if (op->ch1 != -1)
9895 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009896 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009897 if (op->ch2 != -1)
9898 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009899 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009900 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9901 return (total);
9902 case XPATH_OP_RESET:
9903 if (op->ch1 != -1)
9904 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009905 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009906 if (op->ch2 != -1)
9907 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009908 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009909 ctxt->context->node = NULL;
9910 return (total);
9911 case XPATH_OP_COLLECT:{
9912 if (op->ch1 == -1)
9913 return (total);
9914
9915 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009916 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009917
9918 /*
9919 * Optimization for [n] selection where n is a number
9920 */
9921 if ((op->ch2 != -1) &&
9922 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9923 (comp->steps[op->ch2].ch1 == -1) &&
9924 (comp->steps[op->ch2].ch2 != -1) &&
9925 (comp->steps[comp->steps[op->ch2].ch2].op ==
9926 XPATH_OP_VALUE)) {
9927 xmlXPathObjectPtr val;
9928
9929 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9930 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9931 int indx = (int) val->floatval;
9932
9933 if (val->floatval == (float) indx) {
9934 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9935 first, NULL);
9936 return (total);
9937 }
9938 }
9939 }
9940 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9941 return (total);
9942 }
9943 case XPATH_OP_VALUE:
9944 valuePush(ctxt,
9945 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9946 return (0);
9947 case XPATH_OP_SORT:
9948 if (op->ch1 != -1)
9949 total +=
9950 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9951 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009952 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009953 if ((ctxt->value != NULL)
9954 && (ctxt->value->type == XPATH_NODESET)
9955 && (ctxt->value->nodesetval != NULL))
9956 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9957 return (total);
9958 default:
9959 return (xmlXPathCompOpEval(ctxt, op));
9960 }
9961}
9962
9963/**
9964 * xmlXPathCompOpEvalLast:
9965 * @ctxt: the XPath parser context with the compiled expression
9966 * @op: an XPath compiled operation
9967 * @last: the last elem found so far
9968 *
9969 * Evaluate the Precompiled XPath operation searching only the last
9970 * element in document order
9971 *
William M. Brack08171912003-12-29 02:52:11 +00009972 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +00009973 */
9974static int
9975xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9976 xmlNodePtr * last)
9977{
9978 int total = 0, cur;
9979 xmlXPathCompExprPtr comp;
9980 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +00009981 xmlNodePtr bak;
9982 xmlDocPtr bakd;
9983 int pp;
9984 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009985
Daniel Veillard556c6682001-10-06 09:59:51 +00009986 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009987 comp = ctxt->comp;
9988 switch (op->op) {
9989 case XPATH_OP_END:
9990 return (0);
9991 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +00009992 bakd = ctxt->context->doc;
9993 bak = ctxt->context->node;
9994 pp = ctxt->context->proximityPosition;
9995 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009996 total =
9997 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009998 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009999 if ((ctxt->value != NULL)
10000 && (ctxt->value->type == XPATH_NODESET)
10001 && (ctxt->value->nodesetval != NULL)
10002 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10003 /*
10004 * limit tree traversing to first node in the result
10005 */
10006 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10007 *last =
10008 ctxt->value->nodesetval->nodeTab[ctxt->value->
10009 nodesetval->nodeNr -
10010 1];
10011 }
William M. Brackce4fc562004-01-22 02:47:18 +000010012 ctxt->context->doc = bakd;
10013 ctxt->context->node = bak;
10014 ctxt->context->proximityPosition = pp;
10015 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010016 cur =
10017 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010018 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010019 if ((ctxt->value != NULL)
10020 && (ctxt->value->type == XPATH_NODESET)
10021 && (ctxt->value->nodesetval != NULL)
10022 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10023 }
10024 CHECK_TYPE0(XPATH_NODESET);
10025 arg2 = valuePop(ctxt);
10026
10027 CHECK_TYPE0(XPATH_NODESET);
10028 arg1 = valuePop(ctxt);
10029
10030 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10031 arg2->nodesetval);
10032 valuePush(ctxt, arg1);
10033 xmlXPathFreeObject(arg2);
10034 /* optimizer */
10035 if (total > cur)
10036 xmlXPathCompSwap(op);
10037 return (total + cur);
10038 case XPATH_OP_ROOT:
10039 xmlXPathRoot(ctxt);
10040 return (0);
10041 case XPATH_OP_NODE:
10042 if (op->ch1 != -1)
10043 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010044 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010045 if (op->ch2 != -1)
10046 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010047 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010048 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10049 return (total);
10050 case XPATH_OP_RESET:
10051 if (op->ch1 != -1)
10052 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010053 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010054 if (op->ch2 != -1)
10055 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010056 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010057 ctxt->context->node = NULL;
10058 return (total);
10059 case XPATH_OP_COLLECT:{
10060 if (op->ch1 == -1)
10061 return (0);
10062
10063 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010064 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010065
10066 /*
10067 * Optimization for [n] selection where n is a number
10068 */
10069 if ((op->ch2 != -1) &&
10070 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10071 (comp->steps[op->ch2].ch1 == -1) &&
10072 (comp->steps[op->ch2].ch2 != -1) &&
10073 (comp->steps[comp->steps[op->ch2].ch2].op ==
10074 XPATH_OP_VALUE)) {
10075 xmlXPathObjectPtr val;
10076
10077 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10078 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10079 int indx = (int) val->floatval;
10080
10081 if (val->floatval == (float) indx) {
10082 total +=
10083 xmlXPathNodeCollectAndTestNth(ctxt, op,
10084 indx, NULL,
10085 last);
10086 return (total);
10087 }
10088 }
10089 }
10090 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10091 return (total);
10092 }
10093 case XPATH_OP_VALUE:
10094 valuePush(ctxt,
10095 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10096 return (0);
10097 case XPATH_OP_SORT:
10098 if (op->ch1 != -1)
10099 total +=
10100 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10101 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010102 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010103 if ((ctxt->value != NULL)
10104 && (ctxt->value->type == XPATH_NODESET)
10105 && (ctxt->value->nodesetval != NULL))
10106 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10107 return (total);
10108 default:
10109 return (xmlXPathCompOpEval(ctxt, op));
10110 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010111}
10112
Owen Taylor3473f882001-02-23 17:55:21 +000010113/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010114 * xmlXPathCompOpEval:
10115 * @ctxt: the XPath parser context with the compiled expression
10116 * @op: an XPath compiled operation
10117 *
10118 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010119 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010120 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010121static int
10122xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10123{
10124 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010125 int equal, ret;
10126 xmlXPathCompExprPtr comp;
10127 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010128 xmlNodePtr bak;
10129 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010130 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010131 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010132
Daniel Veillard556c6682001-10-06 09:59:51 +000010133 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010134 comp = ctxt->comp;
10135 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010136 case XPATH_OP_END:
10137 return (0);
10138 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010139 bakd = ctxt->context->doc;
10140 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010141 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010142 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010143 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010144 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010145 xmlXPathBooleanFunction(ctxt, 1);
10146 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10147 return (total);
10148 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010149 ctxt->context->doc = bakd;
10150 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010151 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010152 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010153 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010154 if (ctxt->error) {
10155 xmlXPathFreeObject(arg2);
10156 return(0);
10157 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010158 xmlXPathBooleanFunction(ctxt, 1);
10159 arg1 = valuePop(ctxt);
10160 arg1->boolval &= arg2->boolval;
10161 valuePush(ctxt, arg1);
10162 xmlXPathFreeObject(arg2);
10163 return (total);
10164 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010165 bakd = ctxt->context->doc;
10166 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010167 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010168 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010169 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010170 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010171 xmlXPathBooleanFunction(ctxt, 1);
10172 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10173 return (total);
10174 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010175 ctxt->context->doc = bakd;
10176 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010177 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010178 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010179 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010180 if (ctxt->error) {
10181 xmlXPathFreeObject(arg2);
10182 return(0);
10183 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010184 xmlXPathBooleanFunction(ctxt, 1);
10185 arg1 = valuePop(ctxt);
10186 arg1->boolval |= arg2->boolval;
10187 valuePush(ctxt, arg1);
10188 xmlXPathFreeObject(arg2);
10189 return (total);
10190 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010191 bakd = ctxt->context->doc;
10192 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010193 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010194 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010195 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010196 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010197 ctxt->context->doc = bakd;
10198 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010199 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010200 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010201 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010202 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010203 if (op->value)
10204 equal = xmlXPathEqualValues(ctxt);
10205 else
10206 equal = xmlXPathNotEqualValues(ctxt);
10207 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010208 return (total);
10209 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010210 bakd = ctxt->context->doc;
10211 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010212 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010213 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010214 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010215 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010216 ctxt->context->doc = bakd;
10217 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010218 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010219 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010220 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010221 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010222 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10223 valuePush(ctxt, xmlXPathNewBoolean(ret));
10224 return (total);
10225 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010226 bakd = ctxt->context->doc;
10227 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010228 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010229 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010230 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010231 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010232 if (op->ch2 != -1) {
10233 ctxt->context->doc = bakd;
10234 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010235 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010236 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010237 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010238 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010239 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010240 if (op->value == 0)
10241 xmlXPathSubValues(ctxt);
10242 else if (op->value == 1)
10243 xmlXPathAddValues(ctxt);
10244 else if (op->value == 2)
10245 xmlXPathValueFlipSign(ctxt);
10246 else if (op->value == 3) {
10247 CAST_TO_NUMBER;
10248 CHECK_TYPE0(XPATH_NUMBER);
10249 }
10250 return (total);
10251 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010252 bakd = ctxt->context->doc;
10253 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010254 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010255 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010256 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010257 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010258 ctxt->context->doc = bakd;
10259 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010260 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010261 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010262 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010263 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010264 if (op->value == 0)
10265 xmlXPathMultValues(ctxt);
10266 else if (op->value == 1)
10267 xmlXPathDivValues(ctxt);
10268 else if (op->value == 2)
10269 xmlXPathModValues(ctxt);
10270 return (total);
10271 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010272 bakd = ctxt->context->doc;
10273 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010274 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010275 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010276 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010277 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010278 ctxt->context->doc = bakd;
10279 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010280 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010281 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010282 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010283 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010284 CHECK_TYPE0(XPATH_NODESET);
10285 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010286
Daniel Veillardf06307e2001-07-03 10:35:50 +000010287 CHECK_TYPE0(XPATH_NODESET);
10288 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010289
Daniel Veillardf06307e2001-07-03 10:35:50 +000010290 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10291 arg2->nodesetval);
10292 valuePush(ctxt, arg1);
10293 xmlXPathFreeObject(arg2);
10294 return (total);
10295 case XPATH_OP_ROOT:
10296 xmlXPathRoot(ctxt);
10297 return (total);
10298 case XPATH_OP_NODE:
10299 if (op->ch1 != -1)
10300 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010301 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010302 if (op->ch2 != -1)
10303 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010304 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010305 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10306 return (total);
10307 case XPATH_OP_RESET:
10308 if (op->ch1 != -1)
10309 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010310 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010311 if (op->ch2 != -1)
10312 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010313 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010314 ctxt->context->node = NULL;
10315 return (total);
10316 case XPATH_OP_COLLECT:{
10317 if (op->ch1 == -1)
10318 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010319
Daniel Veillardf06307e2001-07-03 10:35:50 +000010320 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010321 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010322
Daniel Veillardf06307e2001-07-03 10:35:50 +000010323 /*
10324 * Optimization for [n] selection where n is a number
10325 */
10326 if ((op->ch2 != -1) &&
10327 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10328 (comp->steps[op->ch2].ch1 == -1) &&
10329 (comp->steps[op->ch2].ch2 != -1) &&
10330 (comp->steps[comp->steps[op->ch2].ch2].op ==
10331 XPATH_OP_VALUE)) {
10332 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010333
Daniel Veillardf06307e2001-07-03 10:35:50 +000010334 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10335 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10336 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010337
Daniel Veillardf06307e2001-07-03 10:35:50 +000010338 if (val->floatval == (float) indx) {
10339 total +=
10340 xmlXPathNodeCollectAndTestNth(ctxt, op,
10341 indx, NULL,
10342 NULL);
10343 return (total);
10344 }
10345 }
10346 }
10347 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10348 return (total);
10349 }
10350 case XPATH_OP_VALUE:
10351 valuePush(ctxt,
10352 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10353 return (total);
10354 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010355 xmlXPathObjectPtr val;
10356
Daniel Veillardf06307e2001-07-03 10:35:50 +000010357 if (op->ch1 != -1)
10358 total +=
10359 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010360 if (op->value5 == NULL) {
10361 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10362 if (val == NULL) {
10363 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10364 return(0);
10365 }
10366 valuePush(ctxt, val);
10367 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010368 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010369
Daniel Veillardf06307e2001-07-03 10:35:50 +000010370 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10371 if (URI == NULL) {
10372 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010373 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010374 op->value4, op->value5);
10375 return (total);
10376 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010377 val = xmlXPathVariableLookupNS(ctxt->context,
10378 op->value4, URI);
10379 if (val == NULL) {
10380 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10381 return(0);
10382 }
10383 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010384 }
10385 return (total);
10386 }
10387 case XPATH_OP_FUNCTION:{
10388 xmlXPathFunction func;
10389 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010390 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010391
10392 if (op->ch1 != -1)
10393 total +=
10394 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010395 if (ctxt->valueNr < op->value) {
10396 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010397 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010398 ctxt->error = XPATH_INVALID_OPERAND;
10399 return (total);
10400 }
10401 for (i = 0; i < op->value; i++)
10402 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10403 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010404 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010405 ctxt->error = XPATH_INVALID_OPERAND;
10406 return (total);
10407 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010408 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000010409 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010410 else {
10411 const xmlChar *URI = NULL;
10412
10413 if (op->value5 == NULL)
10414 func =
10415 xmlXPathFunctionLookup(ctxt->context,
10416 op->value4);
10417 else {
10418 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10419 if (URI == NULL) {
10420 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010421 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010422 op->value4, op->value5);
10423 return (total);
10424 }
10425 func = xmlXPathFunctionLookupNS(ctxt->context,
10426 op->value4, URI);
10427 }
10428 if (func == NULL) {
10429 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010430 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010431 op->value4);
10432 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010433 }
William M. Brackad0e67c2004-12-01 14:35:10 +000010434 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010435 op->cacheURI = (void *) URI;
10436 }
10437 oldFunc = ctxt->context->function;
10438 oldFuncURI = ctxt->context->functionURI;
10439 ctxt->context->function = op->value4;
10440 ctxt->context->functionURI = op->cacheURI;
10441 func(ctxt, op->value);
10442 ctxt->context->function = oldFunc;
10443 ctxt->context->functionURI = oldFuncURI;
10444 return (total);
10445 }
10446 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010447 bakd = ctxt->context->doc;
10448 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000010449 pp = ctxt->context->proximityPosition;
10450 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010451 if (op->ch1 != -1)
10452 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000010453 ctxt->context->contextSize = cs;
10454 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000010455 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000010456 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000010457 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010458 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010459 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010460 ctxt->context->doc = bakd;
10461 ctxt->context->node = bak;
10462 CHECK_ERROR0;
10463 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010464 return (total);
10465 case XPATH_OP_PREDICATE:
10466 case XPATH_OP_FILTER:{
10467 xmlXPathObjectPtr res;
10468 xmlXPathObjectPtr obj, tmp;
10469 xmlNodeSetPtr newset = NULL;
10470 xmlNodeSetPtr oldset;
10471 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000010472 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010473 int i;
10474
10475 /*
10476 * Optimization for ()[1] selection i.e. the first elem
10477 */
10478 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10479 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10480 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10481 xmlXPathObjectPtr val;
10482
10483 val = comp->steps[op->ch2].value4;
10484 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10485 (val->floatval == 1.0)) {
10486 xmlNodePtr first = NULL;
10487
10488 total +=
10489 xmlXPathCompOpEvalFirst(ctxt,
10490 &comp->steps[op->ch1],
10491 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010492 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010493 /*
10494 * The nodeset should be in document order,
10495 * Keep only the first value
10496 */
10497 if ((ctxt->value != NULL) &&
10498 (ctxt->value->type == XPATH_NODESET) &&
10499 (ctxt->value->nodesetval != NULL) &&
10500 (ctxt->value->nodesetval->nodeNr > 1))
10501 ctxt->value->nodesetval->nodeNr = 1;
10502 return (total);
10503 }
10504 }
10505 /*
10506 * Optimization for ()[last()] selection i.e. the last elem
10507 */
10508 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10509 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10510 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10511 int f = comp->steps[op->ch2].ch1;
10512
10513 if ((f != -1) &&
10514 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10515 (comp->steps[f].value5 == NULL) &&
10516 (comp->steps[f].value == 0) &&
10517 (comp->steps[f].value4 != NULL) &&
10518 (xmlStrEqual
10519 (comp->steps[f].value4, BAD_CAST "last"))) {
10520 xmlNodePtr last = NULL;
10521
10522 total +=
10523 xmlXPathCompOpEvalLast(ctxt,
10524 &comp->steps[op->ch1],
10525 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010526 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010527 /*
10528 * The nodeset should be in document order,
10529 * Keep only the last value
10530 */
10531 if ((ctxt->value != NULL) &&
10532 (ctxt->value->type == XPATH_NODESET) &&
10533 (ctxt->value->nodesetval != NULL) &&
10534 (ctxt->value->nodesetval->nodeTab != NULL) &&
10535 (ctxt->value->nodesetval->nodeNr > 1)) {
10536 ctxt->value->nodesetval->nodeTab[0] =
10537 ctxt->value->nodesetval->nodeTab[ctxt->
10538 value->
10539 nodesetval->
10540 nodeNr -
10541 1];
10542 ctxt->value->nodesetval->nodeNr = 1;
10543 }
10544 return (total);
10545 }
10546 }
10547
10548 if (op->ch1 != -1)
10549 total +=
10550 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010551 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010552 if (op->ch2 == -1)
10553 return (total);
10554 if (ctxt->value == NULL)
10555 return (total);
10556
10557 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010558
10559#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010560 /*
10561 * Hum are we filtering the result of an XPointer expression
10562 */
10563 if (ctxt->value->type == XPATH_LOCATIONSET) {
10564 xmlLocationSetPtr newlocset = NULL;
10565 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010566
Daniel Veillardf06307e2001-07-03 10:35:50 +000010567 /*
10568 * Extract the old locset, and then evaluate the result of the
10569 * expression for all the element in the locset. use it to grow
10570 * up a new locset.
10571 */
10572 CHECK_TYPE0(XPATH_LOCATIONSET);
10573 obj = valuePop(ctxt);
10574 oldlocset = obj->user;
10575 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010576
Daniel Veillardf06307e2001-07-03 10:35:50 +000010577 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10578 ctxt->context->contextSize = 0;
10579 ctxt->context->proximityPosition = 0;
10580 if (op->ch2 != -1)
10581 total +=
10582 xmlXPathCompOpEval(ctxt,
10583 &comp->steps[op->ch2]);
10584 res = valuePop(ctxt);
10585 if (res != NULL)
10586 xmlXPathFreeObject(res);
10587 valuePush(ctxt, obj);
10588 CHECK_ERROR0;
10589 return (total);
10590 }
10591 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010592
Daniel Veillardf06307e2001-07-03 10:35:50 +000010593 for (i = 0; i < oldlocset->locNr; i++) {
10594 /*
10595 * Run the evaluation with a node list made of a
10596 * single item in the nodelocset.
10597 */
10598 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010599 ctxt->context->contextSize = oldlocset->locNr;
10600 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010601 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10602 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010603
Daniel Veillardf06307e2001-07-03 10:35:50 +000010604 if (op->ch2 != -1)
10605 total +=
10606 xmlXPathCompOpEval(ctxt,
10607 &comp->steps[op->ch2]);
10608 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010609
Daniel Veillardf06307e2001-07-03 10:35:50 +000010610 /*
10611 * The result of the evaluation need to be tested to
10612 * decided whether the filter succeeded or not
10613 */
10614 res = valuePop(ctxt);
10615 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10616 xmlXPtrLocationSetAdd(newlocset,
10617 xmlXPathObjectCopy
10618 (oldlocset->locTab[i]));
10619 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010620
Daniel Veillardf06307e2001-07-03 10:35:50 +000010621 /*
10622 * Cleanup
10623 */
10624 if (res != NULL)
10625 xmlXPathFreeObject(res);
10626 if (ctxt->value == tmp) {
10627 res = valuePop(ctxt);
10628 xmlXPathFreeObject(res);
10629 }
10630
10631 ctxt->context->node = NULL;
10632 }
10633
10634 /*
10635 * The result is used as the new evaluation locset.
10636 */
10637 xmlXPathFreeObject(obj);
10638 ctxt->context->node = NULL;
10639 ctxt->context->contextSize = -1;
10640 ctxt->context->proximityPosition = -1;
10641 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10642 ctxt->context->node = oldnode;
10643 return (total);
10644 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010645#endif /* LIBXML_XPTR_ENABLED */
10646
Daniel Veillardf06307e2001-07-03 10:35:50 +000010647 /*
10648 * Extract the old set, and then evaluate the result of the
10649 * expression for all the element in the set. use it to grow
10650 * up a new set.
10651 */
10652 CHECK_TYPE0(XPATH_NODESET);
10653 obj = valuePop(ctxt);
10654 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010655
Daniel Veillardf06307e2001-07-03 10:35:50 +000010656 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000010657 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010658 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010659
Daniel Veillardf06307e2001-07-03 10:35:50 +000010660 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10661 ctxt->context->contextSize = 0;
10662 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000010663/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000010664 if (op->ch2 != -1)
10665 total +=
10666 xmlXPathCompOpEval(ctxt,
10667 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010668 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010669 res = valuePop(ctxt);
10670 if (res != NULL)
10671 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000010672*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000010673 valuePush(ctxt, obj);
10674 ctxt->context->node = oldnode;
10675 CHECK_ERROR0;
10676 } else {
10677 /*
10678 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000010679 * Also set the xpath document in case things like
10680 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000010681 */
10682 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010683
Daniel Veillardf06307e2001-07-03 10:35:50 +000010684 for (i = 0; i < oldset->nodeNr; i++) {
10685 /*
10686 * Run the evaluation with a node list made of
10687 * a single item in the nodeset.
10688 */
10689 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000010690 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
10691 (oldset->nodeTab[i]->doc != NULL))
10692 ctxt->context->doc = oldset->nodeTab[i]->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010693 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10694 valuePush(ctxt, tmp);
10695 ctxt->context->contextSize = oldset->nodeNr;
10696 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010697
Daniel Veillardf06307e2001-07-03 10:35:50 +000010698 if (op->ch2 != -1)
10699 total +=
10700 xmlXPathCompOpEval(ctxt,
10701 &comp->steps[op->ch2]);
10702 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010703
Daniel Veillardf06307e2001-07-03 10:35:50 +000010704 /*
William M. Brack08171912003-12-29 02:52:11 +000010705 * The result of the evaluation needs to be tested to
10706 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010707 */
10708 res = valuePop(ctxt);
10709 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10710 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10711 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010712
Daniel Veillardf06307e2001-07-03 10:35:50 +000010713 /*
10714 * Cleanup
10715 */
10716 if (res != NULL)
10717 xmlXPathFreeObject(res);
10718 if (ctxt->value == tmp) {
10719 res = valuePop(ctxt);
10720 xmlXPathFreeObject(res);
10721 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010722
Daniel Veillardf06307e2001-07-03 10:35:50 +000010723 ctxt->context->node = NULL;
10724 }
10725
10726 /*
10727 * The result is used as the new evaluation set.
10728 */
10729 xmlXPathFreeObject(obj);
10730 ctxt->context->node = NULL;
10731 ctxt->context->contextSize = -1;
10732 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000010733 /* may want to move this past the '}' later */
10734 ctxt->context->doc = oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010735 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10736 }
10737 ctxt->context->node = oldnode;
10738 return (total);
10739 }
10740 case XPATH_OP_SORT:
10741 if (op->ch1 != -1)
10742 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010743 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010744 if ((ctxt->value != NULL) &&
10745 (ctxt->value->type == XPATH_NODESET) &&
10746 (ctxt->value->nodesetval != NULL))
10747 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10748 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010749#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010750 case XPATH_OP_RANGETO:{
10751 xmlXPathObjectPtr range;
10752 xmlXPathObjectPtr res, obj;
10753 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010754 xmlLocationSetPtr newlocset = NULL;
10755 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010756 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000010757 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010758
Daniel Veillardf06307e2001-07-03 10:35:50 +000010759 if (op->ch1 != -1)
10760 total +=
10761 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10762 if (op->ch2 == -1)
10763 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010764
William M. Brack08171912003-12-29 02:52:11 +000010765 if (ctxt->value->type == XPATH_LOCATIONSET) {
10766 /*
10767 * Extract the old locset, and then evaluate the result of the
10768 * expression for all the element in the locset. use it to grow
10769 * up a new locset.
10770 */
10771 CHECK_TYPE0(XPATH_LOCATIONSET);
10772 obj = valuePop(ctxt);
10773 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010774
William M. Brack08171912003-12-29 02:52:11 +000010775 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000010776 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000010777 ctxt->context->contextSize = 0;
10778 ctxt->context->proximityPosition = 0;
10779 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10780 res = valuePop(ctxt);
10781 if (res != NULL)
10782 xmlXPathFreeObject(res);
10783 valuePush(ctxt, obj);
10784 CHECK_ERROR0;
10785 return (total);
10786 }
10787 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010788
William M. Brack08171912003-12-29 02:52:11 +000010789 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010790 /*
William M. Brack08171912003-12-29 02:52:11 +000010791 * Run the evaluation with a node list made of a
10792 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010793 */
William M. Brackf7eb7942003-12-31 07:59:17 +000010794 ctxt->context->node = oldlocset->locTab[i]->user;
10795 ctxt->context->contextSize = oldlocset->locNr;
10796 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010797 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10798 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010799
Daniel Veillardf06307e2001-07-03 10:35:50 +000010800 if (op->ch2 != -1)
10801 total +=
10802 xmlXPathCompOpEval(ctxt,
10803 &comp->steps[op->ch2]);
10804 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010805
Daniel Veillardf06307e2001-07-03 10:35:50 +000010806 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000010807 if (res->type == XPATH_LOCATIONSET) {
10808 xmlLocationSetPtr rloc =
10809 (xmlLocationSetPtr)res->user;
10810 for (j=0; j<rloc->locNr; j++) {
10811 range = xmlXPtrNewRange(
10812 oldlocset->locTab[i]->user,
10813 oldlocset->locTab[i]->index,
10814 rloc->locTab[j]->user2,
10815 rloc->locTab[j]->index2);
10816 if (range != NULL) {
10817 xmlXPtrLocationSetAdd(newlocset, range);
10818 }
10819 }
10820 } else {
10821 range = xmlXPtrNewRangeNodeObject(
10822 (xmlNodePtr)oldlocset->locTab[i]->user, res);
10823 if (range != NULL) {
10824 xmlXPtrLocationSetAdd(newlocset,range);
10825 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010826 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010827
Daniel Veillardf06307e2001-07-03 10:35:50 +000010828 /*
10829 * Cleanup
10830 */
10831 if (res != NULL)
10832 xmlXPathFreeObject(res);
10833 if (ctxt->value == tmp) {
10834 res = valuePop(ctxt);
10835 xmlXPathFreeObject(res);
10836 }
10837
10838 ctxt->context->node = NULL;
10839 }
William M. Brack72ee48d2003-12-30 08:30:19 +000010840 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000010841 CHECK_TYPE0(XPATH_NODESET);
10842 obj = valuePop(ctxt);
10843 oldset = obj->nodesetval;
10844 ctxt->context->node = NULL;
10845
10846 newlocset = xmlXPtrLocationSetCreate(NULL);
10847
10848 if (oldset != NULL) {
10849 for (i = 0; i < oldset->nodeNr; i++) {
10850 /*
10851 * Run the evaluation with a node list made of a single item
10852 * in the nodeset.
10853 */
10854 ctxt->context->node = oldset->nodeTab[i];
10855 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10856 valuePush(ctxt, tmp);
10857
10858 if (op->ch2 != -1)
10859 total +=
10860 xmlXPathCompOpEval(ctxt,
10861 &comp->steps[op->ch2]);
10862 CHECK_ERROR0;
10863
William M. Brack08171912003-12-29 02:52:11 +000010864 res = valuePop(ctxt);
10865 range =
10866 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10867 res);
10868 if (range != NULL) {
10869 xmlXPtrLocationSetAdd(newlocset, range);
10870 }
10871
10872 /*
10873 * Cleanup
10874 */
10875 if (res != NULL)
10876 xmlXPathFreeObject(res);
10877 if (ctxt->value == tmp) {
10878 res = valuePop(ctxt);
10879 xmlXPathFreeObject(res);
10880 }
10881
10882 ctxt->context->node = NULL;
10883 }
10884 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010885 }
10886
10887 /*
10888 * The result is used as the new evaluation set.
10889 */
10890 xmlXPathFreeObject(obj);
10891 ctxt->context->node = NULL;
10892 ctxt->context->contextSize = -1;
10893 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010894 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010895 return (total);
10896 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010897#endif /* LIBXML_XPTR_ENABLED */
10898 }
10899 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010900 "XPath: unknown precompiled operation %d\n", op->op);
10901 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010902}
10903
10904/**
10905 * xmlXPathRunEval:
10906 * @ctxt: the XPath parser context with the compiled expression
10907 *
10908 * Evaluate the Precompiled XPath expression in the given context.
10909 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010910static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010911xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10912 xmlXPathCompExprPtr comp;
10913
10914 if ((ctxt == NULL) || (ctxt->comp == NULL))
10915 return;
10916
10917 if (ctxt->valueTab == NULL) {
10918 /* Allocate the value stack */
10919 ctxt->valueTab = (xmlXPathObjectPtr *)
10920 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10921 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010922 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010923 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010924 }
10925 ctxt->valueNr = 0;
10926 ctxt->valueMax = 10;
10927 ctxt->value = NULL;
10928 }
10929 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010930 if(comp->last < 0) {
10931 xmlGenericError(xmlGenericErrorContext,
10932 "xmlXPathRunEval: last is less than zero\n");
10933 return;
10934 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010935 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10936}
10937
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010938/************************************************************************
10939 * *
10940 * Public interfaces *
10941 * *
10942 ************************************************************************/
10943
10944/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010945 * xmlXPathEvalPredicate:
10946 * @ctxt: the XPath context
10947 * @res: the Predicate Expression evaluation result
10948 *
10949 * Evaluate a predicate result for the current node.
10950 * A PredicateExpr is evaluated by evaluating the Expr and converting
10951 * the result to a boolean. If the result is a number, the result will
10952 * be converted to true if the number is equal to the position of the
10953 * context node in the context node list (as returned by the position
10954 * function) and will be converted to false otherwise; if the result
10955 * is not a number, then the result will be converted as if by a call
10956 * to the boolean function.
10957 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010958 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010959 */
10960int
10961xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000010962 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010963 switch (res->type) {
10964 case XPATH_BOOLEAN:
10965 return(res->boolval);
10966 case XPATH_NUMBER:
10967 return(res->floatval == ctxt->proximityPosition);
10968 case XPATH_NODESET:
10969 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010970 if (res->nodesetval == NULL)
10971 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010972 return(res->nodesetval->nodeNr != 0);
10973 case XPATH_STRING:
10974 return((res->stringval != NULL) &&
10975 (xmlStrlen(res->stringval) != 0));
10976 default:
10977 STRANGE
10978 }
10979 return(0);
10980}
10981
10982/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010983 * xmlXPathEvaluatePredicateResult:
10984 * @ctxt: the XPath Parser context
10985 * @res: the Predicate Expression evaluation result
10986 *
10987 * Evaluate a predicate result for the current node.
10988 * A PredicateExpr is evaluated by evaluating the Expr and converting
10989 * the result to a boolean. If the result is a number, the result will
10990 * be converted to true if the number is equal to the position of the
10991 * context node in the context node list (as returned by the position
10992 * function) and will be converted to false otherwise; if the result
10993 * is not a number, then the result will be converted as if by a call
10994 * to the boolean function.
10995 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010996 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010997 */
10998int
10999xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
11000 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000011001 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011002 switch (res->type) {
11003 case XPATH_BOOLEAN:
11004 return(res->boolval);
11005 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000011006#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000011007 return((res->floatval == ctxt->context->proximityPosition) &&
11008 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000011009#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011010 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000011011#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011012 case XPATH_NODESET:
11013 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000011014 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000011015 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011016 return(res->nodesetval->nodeNr != 0);
11017 case XPATH_STRING:
11018 return((res->stringval != NULL) &&
11019 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000011020#ifdef LIBXML_XPTR_ENABLED
11021 case XPATH_LOCATIONSET:{
11022 xmlLocationSetPtr ptr = res->user;
11023 if (ptr == NULL)
11024 return(0);
11025 return (ptr->locNr != 0);
11026 }
11027#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011028 default:
11029 STRANGE
11030 }
11031 return(0);
11032}
11033
11034/**
Daniel Veillard4773df22004-01-23 13:15:13 +000011035 * xmlXPathCtxtCompile:
11036 * @ctxt: an XPath context
11037 * @str: the XPath expression
11038 *
11039 * Compile an XPath expression
11040 *
11041 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
11042 * the caller has to free the object.
11043 */
11044xmlXPathCompExprPtr
11045xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11046 xmlXPathParserContextPtr pctxt;
11047 xmlXPathCompExprPtr comp;
11048
11049 xmlXPathInit();
11050
11051 pctxt = xmlXPathNewParserContext(str, ctxt);
11052 xmlXPathCompileExpr(pctxt);
11053
11054 if( pctxt->error != XPATH_EXPRESSION_OK )
11055 {
11056 xmlXPathFreeParserContext(pctxt);
11057 return (0);
11058 }
11059
11060 if (*pctxt->cur != 0) {
11061 /*
11062 * aleksey: in some cases this line prints *second* error message
11063 * (see bug #78858) and probably this should be fixed.
11064 * However, we are not sure that all error messages are printed
11065 * out in other places. It's not critical so we leave it as-is for now
11066 */
11067 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11068 comp = NULL;
11069 } else {
11070 comp = pctxt->comp;
11071 pctxt->comp = NULL;
11072 }
11073 xmlXPathFreeParserContext(pctxt);
11074 if (comp != NULL) {
11075 comp->expr = xmlStrdup(str);
11076#ifdef DEBUG_EVAL_COUNTS
11077 comp->string = xmlStrdup(str);
11078 comp->nb = 0;
11079#endif
11080 }
11081 return(comp);
11082}
11083
11084/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011085 * xmlXPathCompile:
11086 * @str: the XPath expression
11087 *
11088 * Compile an XPath expression
11089 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000011090 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011091 * the caller has to free the object.
11092 */
11093xmlXPathCompExprPtr
11094xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000011095 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011096}
11097
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011098/**
11099 * xmlXPathCompiledEval:
11100 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000011101 * @ctx: the XPath context
11102 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011103 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000011104 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011105 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000011106 * the caller has to free the object.
11107 */
11108xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011109xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000011110 xmlXPathParserContextPtr ctxt;
11111 xmlXPathObjectPtr res, tmp, init = NULL;
11112 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000011113#ifndef LIBXML_THREAD_ENABLED
11114 static int reentance = 0;
11115#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011116
William M. Brackf13f77f2004-11-12 16:03:48 +000011117 CHECK_CTXT(ctx)
11118
11119 if (comp == NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011120 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011121 xmlXPathInit();
11122
Daniel Veillard81463942001-10-16 12:34:39 +000011123#ifndef LIBXML_THREAD_ENABLED
11124 reentance++;
11125 if (reentance > 1)
11126 xmlXPathDisableOptimizer = 1;
11127#endif
11128
Daniel Veillardf06307e2001-07-03 10:35:50 +000011129#ifdef DEBUG_EVAL_COUNTS
11130 comp->nb++;
11131 if ((comp->string != NULL) && (comp->nb > 100)) {
11132 fprintf(stderr, "100 x %s\n", comp->string);
11133 comp->nb = 0;
11134 }
11135#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011136 ctxt = xmlXPathCompParserContext(comp, ctx);
11137 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011138
11139 if (ctxt->value == NULL) {
11140 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011141 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011142 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011143 } else {
11144 res = valuePop(ctxt);
11145 }
11146
Daniel Veillardf06307e2001-07-03 10:35:50 +000011147
Owen Taylor3473f882001-02-23 17:55:21 +000011148 do {
11149 tmp = valuePop(ctxt);
11150 if (tmp != NULL) {
11151 if (tmp != init)
11152 stack++;
11153 xmlXPathFreeObject(tmp);
11154 }
11155 } while (tmp != NULL);
11156 if ((stack != 0) && (res != NULL)) {
11157 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011158 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011159 stack);
11160 }
11161 if (ctxt->error != XPATH_EXPRESSION_OK) {
11162 xmlXPathFreeObject(res);
11163 res = NULL;
11164 }
11165
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011166
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011167 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011168 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011169#ifndef LIBXML_THREAD_ENABLED
11170 reentance--;
11171#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011172 return(res);
11173}
11174
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011175/**
11176 * xmlXPathEvalExpr:
11177 * @ctxt: the XPath Parser context
11178 *
11179 * Parse and evaluate an XPath expression in the given context,
11180 * then push the result on the context stack
11181 */
11182void
11183xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +000011184 if (ctxt == NULL) return;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011185 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011186 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011187 xmlXPathRunEval(ctxt);
11188}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011189
11190/**
11191 * xmlXPathEval:
11192 * @str: the XPath expression
11193 * @ctx: the XPath context
11194 *
11195 * Evaluate the XPath Location Path in the given context.
11196 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011197 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011198 * the caller has to free the object.
11199 */
11200xmlXPathObjectPtr
11201xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11202 xmlXPathParserContextPtr ctxt;
11203 xmlXPathObjectPtr res, tmp, init = NULL;
11204 int stack = 0;
11205
William M. Brackf13f77f2004-11-12 16:03:48 +000011206 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011207
William M. Brackf13f77f2004-11-12 16:03:48 +000011208 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011209
11210 ctxt = xmlXPathNewParserContext(str, ctx);
11211 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011212
11213 if (ctxt->value == NULL) {
11214 xmlGenericError(xmlGenericErrorContext,
11215 "xmlXPathEval: evaluation failed\n");
11216 res = NULL;
11217 } else if (*ctxt->cur != 0) {
11218 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11219 res = NULL;
11220 } else {
11221 res = valuePop(ctxt);
11222 }
11223
11224 do {
11225 tmp = valuePop(ctxt);
11226 if (tmp != NULL) {
11227 if (tmp != init)
11228 stack++;
11229 xmlXPathFreeObject(tmp);
11230 }
11231 } while (tmp != NULL);
11232 if ((stack != 0) && (res != NULL)) {
11233 xmlGenericError(xmlGenericErrorContext,
11234 "xmlXPathEval: %d object left on the stack\n",
11235 stack);
11236 }
11237 if (ctxt->error != XPATH_EXPRESSION_OK) {
11238 xmlXPathFreeObject(res);
11239 res = NULL;
11240 }
11241
Owen Taylor3473f882001-02-23 17:55:21 +000011242 xmlXPathFreeParserContext(ctxt);
11243 return(res);
11244}
11245
11246/**
11247 * xmlXPathEvalExpression:
11248 * @str: the XPath expression
11249 * @ctxt: the XPath context
11250 *
11251 * Evaluate the XPath expression in the given context.
11252 *
11253 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11254 * the caller has to free the object.
11255 */
11256xmlXPathObjectPtr
11257xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11258 xmlXPathParserContextPtr pctxt;
11259 xmlXPathObjectPtr res, tmp;
11260 int stack = 0;
11261
William M. Brackf13f77f2004-11-12 16:03:48 +000011262 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000011263
William M. Brackf13f77f2004-11-12 16:03:48 +000011264 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000011265
11266 pctxt = xmlXPathNewParserContext(str, ctxt);
11267 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011268
11269 if (*pctxt->cur != 0) {
11270 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11271 res = NULL;
11272 } else {
11273 res = valuePop(pctxt);
11274 }
11275 do {
11276 tmp = valuePop(pctxt);
11277 if (tmp != NULL) {
11278 xmlXPathFreeObject(tmp);
11279 stack++;
11280 }
11281 } while (tmp != NULL);
11282 if ((stack != 0) && (res != NULL)) {
11283 xmlGenericError(xmlGenericErrorContext,
11284 "xmlXPathEvalExpression: %d object left on the stack\n",
11285 stack);
11286 }
11287 xmlXPathFreeParserContext(pctxt);
11288 return(res);
11289}
11290
Daniel Veillard42766c02002-08-22 20:52:17 +000011291/************************************************************************
11292 * *
11293 * Extra functions not pertaining to the XPath spec *
11294 * *
11295 ************************************************************************/
11296/**
11297 * xmlXPathEscapeUriFunction:
11298 * @ctxt: the XPath Parser context
11299 * @nargs: the number of arguments
11300 *
11301 * Implement the escape-uri() XPath function
11302 * string escape-uri(string $str, bool $escape-reserved)
11303 *
11304 * This function applies the URI escaping rules defined in section 2 of [RFC
11305 * 2396] to the string supplied as $uri-part, which typically represents all
11306 * or part of a URI. The effect of the function is to replace any special
11307 * character in the string by an escape sequence of the form %xx%yy...,
11308 * where xxyy... is the hexadecimal representation of the octets used to
11309 * represent the character in UTF-8.
11310 *
11311 * The set of characters that are escaped depends on the setting of the
11312 * boolean argument $escape-reserved.
11313 *
11314 * If $escape-reserved is true, all characters are escaped other than lower
11315 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11316 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11317 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11318 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11319 * A-F).
11320 *
11321 * If $escape-reserved is false, the behavior differs in that characters
11322 * referred to in [RFC 2396] as reserved characters are not escaped. These
11323 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11324 *
11325 * [RFC 2396] does not define whether escaped URIs should use lower case or
11326 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11327 * compared using string comparison functions, this function must always use
11328 * the upper-case letters A-F.
11329 *
11330 * Generally, $escape-reserved should be set to true when escaping a string
11331 * that is to form a single part of a URI, and to false when escaping an
11332 * entire URI or URI reference.
11333 *
11334 * In the case of non-ascii characters, the string is encoded according to
11335 * utf-8 and then converted according to RFC 2396.
11336 *
11337 * Examples
11338 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11339 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11340 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11341 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11342 *
11343 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011344static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011345xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11346 xmlXPathObjectPtr str;
11347 int escape_reserved;
11348 xmlBufferPtr target;
11349 xmlChar *cptr;
11350 xmlChar escape[4];
11351
11352 CHECK_ARITY(2);
11353
11354 escape_reserved = xmlXPathPopBoolean(ctxt);
11355
11356 CAST_TO_STRING;
11357 str = valuePop(ctxt);
11358
11359 target = xmlBufferCreate();
11360
11361 escape[0] = '%';
11362 escape[3] = 0;
11363
11364 if (target) {
11365 for (cptr = str->stringval; *cptr; cptr++) {
11366 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11367 (*cptr >= 'a' && *cptr <= 'z') ||
11368 (*cptr >= '0' && *cptr <= '9') ||
11369 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11370 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11371 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11372 (*cptr == '%' &&
11373 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11374 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11375 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11376 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11377 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11378 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11379 (!escape_reserved &&
11380 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11381 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11382 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11383 *cptr == ','))) {
11384 xmlBufferAdd(target, cptr, 1);
11385 } else {
11386 if ((*cptr >> 4) < 10)
11387 escape[1] = '0' + (*cptr >> 4);
11388 else
11389 escape[1] = 'A' - 10 + (*cptr >> 4);
11390 if ((*cptr & 0xF) < 10)
11391 escape[2] = '0' + (*cptr & 0xF);
11392 else
11393 escape[2] = 'A' - 10 + (*cptr & 0xF);
11394
11395 xmlBufferAdd(target, &escape[0], 3);
11396 }
11397 }
11398 }
11399 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11400 xmlBufferFree(target);
11401 xmlXPathFreeObject(str);
11402}
11403
Owen Taylor3473f882001-02-23 17:55:21 +000011404/**
11405 * xmlXPathRegisterAllFunctions:
11406 * @ctxt: the XPath context
11407 *
11408 * Registers all default XPath functions in this context
11409 */
11410void
11411xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11412{
11413 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11414 xmlXPathBooleanFunction);
11415 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11416 xmlXPathCeilingFunction);
11417 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11418 xmlXPathCountFunction);
11419 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11420 xmlXPathConcatFunction);
11421 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11422 xmlXPathContainsFunction);
11423 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11424 xmlXPathIdFunction);
11425 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11426 xmlXPathFalseFunction);
11427 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11428 xmlXPathFloorFunction);
11429 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11430 xmlXPathLastFunction);
11431 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11432 xmlXPathLangFunction);
11433 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11434 xmlXPathLocalNameFunction);
11435 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11436 xmlXPathNotFunction);
11437 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11438 xmlXPathNameFunction);
11439 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11440 xmlXPathNamespaceURIFunction);
11441 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11442 xmlXPathNormalizeFunction);
11443 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11444 xmlXPathNumberFunction);
11445 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11446 xmlXPathPositionFunction);
11447 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11448 xmlXPathRoundFunction);
11449 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11450 xmlXPathStringFunction);
11451 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11452 xmlXPathStringLengthFunction);
11453 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11454 xmlXPathStartsWithFunction);
11455 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11456 xmlXPathSubstringFunction);
11457 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11458 xmlXPathSubstringBeforeFunction);
11459 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11460 xmlXPathSubstringAfterFunction);
11461 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11462 xmlXPathSumFunction);
11463 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11464 xmlXPathTrueFunction);
11465 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11466 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011467
11468 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11469 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11470 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011471}
11472
11473#endif /* LIBXML_XPATH_ENABLED */