blob: 8076b3c4c6ee3c0a3b056e37623d0a03573dd7be [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
Daniel Veillard4432df22003-09-28 18:58:27 +000067#if defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XPATH_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
778 for (i = 0;((i < depth) && (i < 25));i++)
779 shift[2 * i] = shift[2 * i + 1] = ' ';
780 shift[2 * i] = shift[2 * i + 1] = 0;
781
782 fprintf(output, shift);
783
784 if (cur == NULL) {
785 fprintf(output, "Object is empty (NULL)\n");
786 return;
787 }
788 switch(cur->type) {
789 case XPATH_UNDEFINED:
790 fprintf(output, "Object is uninitialized\n");
791 break;
792 case XPATH_NODESET:
793 fprintf(output, "Object is a Node Set :\n");
794 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
795 break;
796 case XPATH_XSLT_TREE:
797 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000798 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000799 break;
800 case XPATH_BOOLEAN:
801 fprintf(output, "Object is a Boolean : ");
802 if (cur->boolval) fprintf(output, "true\n");
803 else fprintf(output, "false\n");
804 break;
805 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000806 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000807 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000808 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000809 break;
810 case -1:
811 fprintf(output, "Object is a number : -Infinity\n");
812 break;
813 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000814 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000815 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000816 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
817 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000818 } else {
819 fprintf(output, "Object is a number : %0g\n", cur->floatval);
820 }
821 }
Owen Taylor3473f882001-02-23 17:55:21 +0000822 break;
823 case XPATH_STRING:
824 fprintf(output, "Object is a string : ");
825 xmlDebugDumpString(output, cur->stringval);
826 fprintf(output, "\n");
827 break;
828 case XPATH_POINT:
829 fprintf(output, "Object is a point : index %d in node", cur->index);
830 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
831 fprintf(output, "\n");
832 break;
833 case XPATH_RANGE:
834 if ((cur->user2 == NULL) ||
835 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
836 fprintf(output, "Object is a collapsed range :\n");
837 fprintf(output, shift);
838 if (cur->index >= 0)
839 fprintf(output, "index %d in ", cur->index);
840 fprintf(output, "node\n");
841 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
842 depth + 1);
843 } else {
844 fprintf(output, "Object is a range :\n");
845 fprintf(output, shift);
846 fprintf(output, "From ");
847 if (cur->index >= 0)
848 fprintf(output, "index %d in ", cur->index);
849 fprintf(output, "node\n");
850 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
851 depth + 1);
852 fprintf(output, shift);
853 fprintf(output, "To ");
854 if (cur->index2 >= 0)
855 fprintf(output, "index %d in ", cur->index2);
856 fprintf(output, "node\n");
857 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
858 depth + 1);
859 fprintf(output, "\n");
860 }
861 break;
862 case XPATH_LOCATIONSET:
863#if defined(LIBXML_XPTR_ENABLED)
864 fprintf(output, "Object is a Location Set:\n");
865 xmlXPathDebugDumpLocationSet(output,
866 (xmlLocationSetPtr) cur->user, depth);
867#endif
868 break;
869 case XPATH_USERS:
870 fprintf(output, "Object is user defined\n");
871 break;
872 }
873}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000874
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000875static void
876xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000877 xmlXPathStepOpPtr op, int depth) {
878 int i;
879 char shift[100];
880
881 for (i = 0;((i < depth) && (i < 25));i++)
882 shift[2 * i] = shift[2 * i + 1] = ' ';
883 shift[2 * i] = shift[2 * i + 1] = 0;
884
885 fprintf(output, shift);
886 if (op == NULL) {
887 fprintf(output, "Step is NULL\n");
888 return;
889 }
890 switch (op->op) {
891 case XPATH_OP_END:
892 fprintf(output, "END"); break;
893 case XPATH_OP_AND:
894 fprintf(output, "AND"); break;
895 case XPATH_OP_OR:
896 fprintf(output, "OR"); break;
897 case XPATH_OP_EQUAL:
898 if (op->value)
899 fprintf(output, "EQUAL =");
900 else
901 fprintf(output, "EQUAL !=");
902 break;
903 case XPATH_OP_CMP:
904 if (op->value)
905 fprintf(output, "CMP <");
906 else
907 fprintf(output, "CMP >");
908 if (!op->value2)
909 fprintf(output, "=");
910 break;
911 case XPATH_OP_PLUS:
912 if (op->value == 0)
913 fprintf(output, "PLUS -");
914 else if (op->value == 1)
915 fprintf(output, "PLUS +");
916 else if (op->value == 2)
917 fprintf(output, "PLUS unary -");
918 else if (op->value == 3)
919 fprintf(output, "PLUS unary - -");
920 break;
921 case XPATH_OP_MULT:
922 if (op->value == 0)
923 fprintf(output, "MULT *");
924 else if (op->value == 1)
925 fprintf(output, "MULT div");
926 else
927 fprintf(output, "MULT mod");
928 break;
929 case XPATH_OP_UNION:
930 fprintf(output, "UNION"); break;
931 case XPATH_OP_ROOT:
932 fprintf(output, "ROOT"); break;
933 case XPATH_OP_NODE:
934 fprintf(output, "NODE"); break;
935 case XPATH_OP_RESET:
936 fprintf(output, "RESET"); break;
937 case XPATH_OP_SORT:
938 fprintf(output, "SORT"); break;
939 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000940 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
941 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
942 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000943 const xmlChar *prefix = op->value4;
944 const xmlChar *name = op->value5;
945
946 fprintf(output, "COLLECT ");
947 switch (axis) {
948 case AXIS_ANCESTOR:
949 fprintf(output, " 'ancestors' "); break;
950 case AXIS_ANCESTOR_OR_SELF:
951 fprintf(output, " 'ancestors-or-self' "); break;
952 case AXIS_ATTRIBUTE:
953 fprintf(output, " 'attributes' "); break;
954 case AXIS_CHILD:
955 fprintf(output, " 'child' "); break;
956 case AXIS_DESCENDANT:
957 fprintf(output, " 'descendant' "); break;
958 case AXIS_DESCENDANT_OR_SELF:
959 fprintf(output, " 'descendant-or-self' "); break;
960 case AXIS_FOLLOWING:
961 fprintf(output, " 'following' "); break;
962 case AXIS_FOLLOWING_SIBLING:
963 fprintf(output, " 'following-siblings' "); break;
964 case AXIS_NAMESPACE:
965 fprintf(output, " 'namespace' "); break;
966 case AXIS_PARENT:
967 fprintf(output, " 'parent' "); break;
968 case AXIS_PRECEDING:
969 fprintf(output, " 'preceding' "); break;
970 case AXIS_PRECEDING_SIBLING:
971 fprintf(output, " 'preceding-sibling' "); break;
972 case AXIS_SELF:
973 fprintf(output, " 'self' "); break;
974 }
975 switch (test) {
976 case NODE_TEST_NONE:
977 fprintf(output, "'none' "); break;
978 case NODE_TEST_TYPE:
979 fprintf(output, "'type' "); break;
980 case NODE_TEST_PI:
981 fprintf(output, "'PI' "); break;
982 case NODE_TEST_ALL:
983 fprintf(output, "'all' "); break;
984 case NODE_TEST_NS:
985 fprintf(output, "'namespace' "); break;
986 case NODE_TEST_NAME:
987 fprintf(output, "'name' "); break;
988 }
989 switch (type) {
990 case NODE_TYPE_NODE:
991 fprintf(output, "'node' "); break;
992 case NODE_TYPE_COMMENT:
993 fprintf(output, "'comment' "); break;
994 case NODE_TYPE_TEXT:
995 fprintf(output, "'text' "); break;
996 case NODE_TYPE_PI:
997 fprintf(output, "'PI' "); break;
998 }
999 if (prefix != NULL)
1000 fprintf(output, "%s:", prefix);
1001 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001002 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001003 break;
1004
1005 }
1006 case XPATH_OP_VALUE: {
1007 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1008
1009 fprintf(output, "ELEM ");
1010 xmlXPathDebugDumpObject(output, object, 0);
1011 goto finish;
1012 }
1013 case XPATH_OP_VARIABLE: {
1014 const xmlChar *prefix = op->value5;
1015 const xmlChar *name = op->value4;
1016
1017 if (prefix != NULL)
1018 fprintf(output, "VARIABLE %s:%s", prefix, name);
1019 else
1020 fprintf(output, "VARIABLE %s", name);
1021 break;
1022 }
1023 case XPATH_OP_FUNCTION: {
1024 int nbargs = op->value;
1025 const xmlChar *prefix = op->value5;
1026 const xmlChar *name = op->value4;
1027
1028 if (prefix != NULL)
1029 fprintf(output, "FUNCTION %s:%s(%d args)",
1030 prefix, name, nbargs);
1031 else
1032 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1033 break;
1034 }
1035 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1036 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001037 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001038#ifdef LIBXML_XPTR_ENABLED
1039 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1040#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001041 default:
1042 fprintf(output, "UNKNOWN %d\n", op->op); return;
1043 }
1044 fprintf(output, "\n");
1045finish:
1046 if (op->ch1 >= 0)
1047 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1048 if (op->ch2 >= 0)
1049 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1050}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001051
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001052/**
1053 * xmlXPathDebugDumpCompExpr:
1054 * @output: the FILE * for the output
1055 * @comp: the precompiled XPath expression
1056 * @depth: the indentation level.
1057 *
1058 * Dumps the tree of the compiled XPath expression.
1059 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001060void
1061xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1062 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001063 int i;
1064 char shift[100];
1065
1066 for (i = 0;((i < depth) && (i < 25));i++)
1067 shift[2 * i] = shift[2 * i + 1] = ' ';
1068 shift[2 * i] = shift[2 * i + 1] = 0;
1069
1070 fprintf(output, shift);
1071
1072 if (comp == NULL) {
1073 fprintf(output, "Compiled Expression is NULL\n");
1074 return;
1075 }
1076 fprintf(output, "Compiled Expression : %d elements\n",
1077 comp->nbStep);
1078 i = comp->last;
1079 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1080}
Daniel Veillard017b1082001-06-21 11:20:21 +00001081#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001082
1083/************************************************************************
1084 * *
1085 * Parser stacks related functions and macros *
1086 * *
1087 ************************************************************************/
1088
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001089/**
1090 * valuePop:
1091 * @ctxt: an XPath evaluation context
1092 *
1093 * Pops the top XPath object from the value stack
1094 *
1095 * Returns the XPath object just removed
1096 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001097extern xmlXPathObjectPtr
1098valuePop(xmlXPathParserContextPtr ctxt)
1099{
1100 xmlXPathObjectPtr ret;
1101
1102 if (ctxt->valueNr <= 0)
1103 return (0);
1104 ctxt->valueNr--;
1105 if (ctxt->valueNr > 0)
1106 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1107 else
1108 ctxt->value = NULL;
1109 ret = ctxt->valueTab[ctxt->valueNr];
1110 ctxt->valueTab[ctxt->valueNr] = 0;
1111 return (ret);
1112}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001113/**
1114 * valuePush:
1115 * @ctxt: an XPath evaluation context
1116 * @value: the XPath object
1117 *
1118 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001119 *
1120 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001121 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001122extern int
1123valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1124{
1125 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001126 xmlXPathObjectPtr *tmp;
1127
1128 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1129 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00001130 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001131 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00001132 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1133 return (0);
1134 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001135 ctxt->valueMax *= 2;
1136 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00001137 }
1138 ctxt->valueTab[ctxt->valueNr] = value;
1139 ctxt->value = value;
1140 return (ctxt->valueNr++);
1141}
Owen Taylor3473f882001-02-23 17:55:21 +00001142
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001143/**
1144 * xmlXPathPopBoolean:
1145 * @ctxt: an XPath parser context
1146 *
1147 * Pops a boolean from the stack, handling conversion if needed.
1148 * Check error with #xmlXPathCheckError.
1149 *
1150 * Returns the boolean
1151 */
1152int
1153xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1154 xmlXPathObjectPtr obj;
1155 int ret;
1156
1157 obj = valuePop(ctxt);
1158 if (obj == NULL) {
1159 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1160 return(0);
1161 }
William M. Brack08171912003-12-29 02:52:11 +00001162 if (obj->type != XPATH_BOOLEAN)
1163 ret = xmlXPathCastToBoolean(obj);
1164 else
1165 ret = obj->boolval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001166 xmlXPathFreeObject(obj);
1167 return(ret);
1168}
1169
1170/**
1171 * xmlXPathPopNumber:
1172 * @ctxt: an XPath parser context
1173 *
1174 * Pops a number from the stack, handling conversion if needed.
1175 * Check error with #xmlXPathCheckError.
1176 *
1177 * Returns the number
1178 */
1179double
1180xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1181 xmlXPathObjectPtr obj;
1182 double ret;
1183
1184 obj = valuePop(ctxt);
1185 if (obj == NULL) {
1186 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1187 return(0);
1188 }
William M. Brack08171912003-12-29 02:52:11 +00001189 if (obj->type != XPATH_NUMBER)
1190 ret = xmlXPathCastToNumber(obj);
1191 else
1192 ret = obj->floatval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001193 xmlXPathFreeObject(obj);
1194 return(ret);
1195}
1196
1197/**
1198 * xmlXPathPopString:
1199 * @ctxt: an XPath parser context
1200 *
1201 * Pops a string from the stack, handling conversion if needed.
1202 * Check error with #xmlXPathCheckError.
1203 *
1204 * Returns the string
1205 */
1206xmlChar *
1207xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1208 xmlXPathObjectPtr obj;
1209 xmlChar * ret;
1210
1211 obj = valuePop(ctxt);
1212 if (obj == NULL) {
1213 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1214 return(NULL);
1215 }
William M. Brack08171912003-12-29 02:52:11 +00001216 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001217 /* TODO: needs refactoring somewhere else */
1218 if (obj->stringval == ret)
1219 obj->stringval = NULL;
1220 xmlXPathFreeObject(obj);
1221 return(ret);
1222}
1223
1224/**
1225 * xmlXPathPopNodeSet:
1226 * @ctxt: an XPath parser context
1227 *
1228 * Pops a node-set from the stack, handling conversion if needed.
1229 * Check error with #xmlXPathCheckError.
1230 *
1231 * Returns the node-set
1232 */
1233xmlNodeSetPtr
1234xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1235 xmlXPathObjectPtr obj;
1236 xmlNodeSetPtr ret;
1237
1238 if (ctxt->value == NULL) {
1239 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1240 return(NULL);
1241 }
1242 if (!xmlXPathStackIsNodeSet(ctxt)) {
1243 xmlXPathSetTypeError(ctxt);
1244 return(NULL);
1245 }
1246 obj = valuePop(ctxt);
1247 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00001248#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00001249 /* to fix memory leak of not clearing obj->user */
1250 if (obj->boolval && obj->user != NULL)
1251 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00001252#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001253 xmlXPathFreeNodeSetList(obj);
1254 return(ret);
1255}
1256
1257/**
1258 * xmlXPathPopExternal:
1259 * @ctxt: an XPath parser context
1260 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001261 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001262 * Check error with #xmlXPathCheckError.
1263 *
1264 * Returns the object
1265 */
1266void *
1267xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1268 xmlXPathObjectPtr obj;
1269 void * ret;
1270
1271 if (ctxt->value == NULL) {
1272 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1273 return(NULL);
1274 }
1275 if (ctxt->value->type != XPATH_USERS) {
1276 xmlXPathSetTypeError(ctxt);
1277 return(NULL);
1278 }
1279 obj = valuePop(ctxt);
1280 ret = obj->user;
1281 xmlXPathFreeObject(obj);
1282 return(ret);
1283}
1284
Owen Taylor3473f882001-02-23 17:55:21 +00001285/*
1286 * Macros for accessing the content. Those should be used only by the parser,
1287 * and not exported.
1288 *
1289 * Dirty macros, i.e. one need to make assumption on the context to use them
1290 *
1291 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1292 * CUR returns the current xmlChar value, i.e. a 8 bit value
1293 * in ISO-Latin or UTF-8.
1294 * This should be used internally by the parser
1295 * only to compare to ASCII values otherwise it would break when
1296 * running with UTF-8 encoding.
1297 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1298 * to compare on ASCII based substring.
1299 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1300 * strings within the parser.
1301 * CURRENT Returns the current char value, with the full decoding of
1302 * UTF-8 if we are using this mode. It returns an int.
1303 * NEXT Skip to the next character, this does the proper decoding
1304 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1305 * It returns the pointer to the current xmlChar.
1306 */
1307
1308#define CUR (*ctxt->cur)
1309#define SKIP(val) ctxt->cur += (val)
1310#define NXT(val) ctxt->cur[(val)]
1311#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001312#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1313
1314#define COPY_BUF(l,b,i,v) \
1315 if (l == 1) b[i++] = (xmlChar) v; \
1316 else i += xmlCopyChar(l,&b[i],v)
1317
1318#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001319
1320#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001321 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001322
1323#define CURRENT (*ctxt->cur)
1324#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1325
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001326
1327#ifndef DBL_DIG
1328#define DBL_DIG 16
1329#endif
1330#ifndef DBL_EPSILON
1331#define DBL_EPSILON 1E-9
1332#endif
1333
1334#define UPPER_DOUBLE 1E9
1335#define LOWER_DOUBLE 1E-5
1336
1337#define INTEGER_DIGITS DBL_DIG
1338#define FRACTION_DIGITS (DBL_DIG + 1)
1339#define EXPONENT_DIGITS (3 + 2)
1340
1341/**
1342 * xmlXPathFormatNumber:
1343 * @number: number to format
1344 * @buffer: output buffer
1345 * @buffersize: size of output buffer
1346 *
1347 * Convert the number into a string representation.
1348 */
1349static void
1350xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1351{
Daniel Veillardcda96922001-08-21 10:56:31 +00001352 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001353 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001354 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001355 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001356 break;
1357 case -1:
1358 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001359 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001360 break;
1361 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001362 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001363 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001364 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001365 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001366 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001367 } else if (number == ((int) number)) {
1368 char work[30];
1369 char *ptr, *cur;
1370 int res, value = (int) number;
1371
1372 ptr = &buffer[0];
1373 if (value < 0) {
1374 *ptr++ = '-';
1375 value = -value;
1376 }
1377 if (value == 0) {
1378 *ptr++ = '0';
1379 } else {
1380 cur = &work[0];
1381 while (value != 0) {
1382 res = value % 10;
1383 value = value / 10;
1384 *cur++ = '0' + res;
1385 }
1386 cur--;
1387 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1388 *ptr++ = *cur--;
1389 }
1390 }
1391 if (ptr - buffer < buffersize) {
1392 *ptr = 0;
1393 } else if (buffersize > 0) {
1394 ptr--;
1395 *ptr = 0;
1396 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001397 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001398 /* 3 is sign, decimal point, and terminating zero */
1399 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1400 int integer_place, fraction_place;
1401 char *ptr;
1402 char *after_fraction;
1403 double absolute_value;
1404 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001405
Bjorn Reese70a9da52001-04-21 16:57:29 +00001406 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001407
Bjorn Reese70a9da52001-04-21 16:57:29 +00001408 /*
1409 * First choose format - scientific or regular floating point.
1410 * In either case, result is in work, and after_fraction points
1411 * just past the fractional part.
1412 */
1413 if ( ((absolute_value > UPPER_DOUBLE) ||
1414 (absolute_value < LOWER_DOUBLE)) &&
1415 (absolute_value != 0.0) ) {
1416 /* Use scientific notation */
1417 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1418 fraction_place = DBL_DIG - 1;
1419 snprintf(work, sizeof(work),"%*.*e",
1420 integer_place, fraction_place, number);
1421 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001422 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001423 else {
1424 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001425 if (absolute_value > 0.0)
1426 integer_place = 1 + (int)log10(absolute_value);
1427 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001428 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001429 fraction_place = (integer_place > 0)
1430 ? DBL_DIG - integer_place
1431 : DBL_DIG;
1432 size = snprintf(work, sizeof(work), "%0.*f",
1433 fraction_place, number);
1434 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001435 }
1436
Bjorn Reese70a9da52001-04-21 16:57:29 +00001437 /* Remove fractional trailing zeroes */
1438 ptr = after_fraction;
1439 while (*(--ptr) == '0')
1440 ;
1441 if (*ptr != '.')
1442 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001443 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001444
1445 /* Finally copy result back to caller */
1446 size = strlen(work) + 1;
1447 if (size > buffersize) {
1448 work[buffersize - 1] = 0;
1449 size = buffersize;
1450 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001451 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001452 }
1453 break;
1454 }
1455}
1456
Owen Taylor3473f882001-02-23 17:55:21 +00001457
1458/************************************************************************
1459 * *
1460 * Routines to handle NodeSets *
1461 * *
1462 ************************************************************************/
1463
1464/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001465 * xmlXPathOrderDocElems:
1466 * @doc: an input document
1467 *
1468 * Call this routine to speed up XPath computation on static documents.
1469 * This stamps all the element nodes with the document order
1470 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00001471 * field, the value stored is actually - the node number (starting at -1)
1472 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001473 *
William M. Brack08171912003-12-29 02:52:11 +00001474 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001475 * of error.
1476 */
1477long
1478xmlXPathOrderDocElems(xmlDocPtr doc) {
1479 long count = 0;
1480 xmlNodePtr cur;
1481
1482 if (doc == NULL)
1483 return(-1);
1484 cur = doc->children;
1485 while (cur != NULL) {
1486 if (cur->type == XML_ELEMENT_NODE) {
1487 cur->content = (void *) (-(++count));
1488 if (cur->children != NULL) {
1489 cur = cur->children;
1490 continue;
1491 }
1492 }
1493 if (cur->next != NULL) {
1494 cur = cur->next;
1495 continue;
1496 }
1497 do {
1498 cur = cur->parent;
1499 if (cur == NULL)
1500 break;
1501 if (cur == (xmlNodePtr) doc) {
1502 cur = NULL;
1503 break;
1504 }
1505 if (cur->next != NULL) {
1506 cur = cur->next;
1507 break;
1508 }
1509 } while (cur != NULL);
1510 }
1511 return(count);
1512}
1513
1514/**
Owen Taylor3473f882001-02-23 17:55:21 +00001515 * xmlXPathCmpNodes:
1516 * @node1: the first node
1517 * @node2: the second node
1518 *
1519 * Compare two nodes w.r.t document order
1520 *
1521 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00001522 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001523 */
1524int
1525xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1526 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001527 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001528 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001529 xmlNodePtr cur, root;
1530
1531 if ((node1 == NULL) || (node2 == NULL))
1532 return(-2);
1533 /*
1534 * a couple of optimizations which will avoid computations in most cases
1535 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001536 if (node1->type == XML_ATTRIBUTE_NODE) {
1537 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001538 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001539 node1 = node1->parent;
1540 }
1541 if (node2->type == XML_ATTRIBUTE_NODE) {
1542 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001543 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001544 node2 = node2->parent;
1545 }
1546 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001547 if (attr1 == attr2) {
1548 /* not required, but we keep attributes in order */
1549 if (attr1 != 0) {
1550 cur = attrNode2->prev;
1551 while (cur != NULL) {
1552 if (cur == attrNode1)
1553 return (1);
1554 cur = cur->prev;
1555 }
1556 return (-1);
1557 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001558 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001559 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001560 if (attr2 == 1)
1561 return(1);
1562 return(-1);
1563 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001564 if ((node1->type == XML_NAMESPACE_DECL) ||
1565 (node2->type == XML_NAMESPACE_DECL))
1566 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001567 if (node1 == node2->prev)
1568 return(1);
1569 if (node1 == node2->next)
1570 return(-1);
1571
1572 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001573 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001574 */
1575 if ((node1->type == XML_ELEMENT_NODE) &&
1576 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001577 (0 > (long) node1->content) &&
1578 (0 > (long) node2->content) &&
1579 (node1->doc == node2->doc)) {
1580 long l1, l2;
1581
1582 l1 = -((long) node1->content);
1583 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001584 if (l1 < l2)
1585 return(1);
1586 if (l1 > l2)
1587 return(-1);
1588 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001589
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001590 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001591 * compute depth to root
1592 */
1593 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1594 if (cur == node1)
1595 return(1);
1596 depth2++;
1597 }
1598 root = cur;
1599 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1600 if (cur == node2)
1601 return(-1);
1602 depth1++;
1603 }
1604 /*
1605 * Distinct document (or distinct entities :-( ) case.
1606 */
1607 if (root != cur) {
1608 return(-2);
1609 }
1610 /*
1611 * get the nearest common ancestor.
1612 */
1613 while (depth1 > depth2) {
1614 depth1--;
1615 node1 = node1->parent;
1616 }
1617 while (depth2 > depth1) {
1618 depth2--;
1619 node2 = node2->parent;
1620 }
1621 while (node1->parent != node2->parent) {
1622 node1 = node1->parent;
1623 node2 = node2->parent;
1624 /* should not happen but just in case ... */
1625 if ((node1 == NULL) || (node2 == NULL))
1626 return(-2);
1627 }
1628 /*
1629 * Find who's first.
1630 */
Daniel Veillardf49be472004-02-17 11:48:18 +00001631 if (node1 == node2->prev)
1632 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001633 if (node1 == node2->next)
1634 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00001635 /*
1636 * Speedup using document order if availble.
1637 */
1638 if ((node1->type == XML_ELEMENT_NODE) &&
1639 (node2->type == XML_ELEMENT_NODE) &&
1640 (0 > (long) node1->content) &&
1641 (0 > (long) node2->content) &&
1642 (node1->doc == node2->doc)) {
1643 long l1, l2;
1644
1645 l1 = -((long) node1->content);
1646 l2 = -((long) node2->content);
1647 if (l1 < l2)
1648 return(1);
1649 if (l1 > l2)
1650 return(-1);
1651 }
1652
Owen Taylor3473f882001-02-23 17:55:21 +00001653 for (cur = node1->next;cur != NULL;cur = cur->next)
1654 if (cur == node2)
1655 return(1);
1656 return(-1); /* assume there is no sibling list corruption */
1657}
1658
1659/**
1660 * xmlXPathNodeSetSort:
1661 * @set: the node set
1662 *
1663 * Sort the node set in document order
1664 */
1665void
1666xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001667 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001668 xmlNodePtr tmp;
1669
1670 if (set == NULL)
1671 return;
1672
1673 /* Use Shell's sort to sort the node-set */
1674 len = set->nodeNr;
1675 for (incr = len / 2; incr > 0; incr /= 2) {
1676 for (i = incr; i < len; i++) {
1677 j = i - incr;
1678 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001679 if (xmlXPathCmpNodes(set->nodeTab[j],
1680 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001681 tmp = set->nodeTab[j];
1682 set->nodeTab[j] = set->nodeTab[j + incr];
1683 set->nodeTab[j + incr] = tmp;
1684 j -= incr;
1685 } else
1686 break;
1687 }
1688 }
1689 }
1690}
1691
1692#define XML_NODESET_DEFAULT 10
1693/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001694 * xmlXPathNodeSetDupNs:
1695 * @node: the parent node of the namespace XPath node
1696 * @ns: the libxml namespace declaration node.
1697 *
1698 * Namespace node in libxml don't match the XPath semantic. In a node set
1699 * the namespace nodes are duplicated and the next pointer is set to the
1700 * parent node in the XPath semantic.
1701 *
1702 * Returns the newly created object.
1703 */
1704static xmlNodePtr
1705xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1706 xmlNsPtr cur;
1707
1708 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1709 return(NULL);
1710 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1711 return((xmlNodePtr) ns);
1712
1713 /*
1714 * Allocate a new Namespace and fill the fields.
1715 */
1716 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1717 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001718 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001719 return(NULL);
1720 }
1721 memset(cur, 0, sizeof(xmlNs));
1722 cur->type = XML_NAMESPACE_DECL;
1723 if (ns->href != NULL)
1724 cur->href = xmlStrdup(ns->href);
1725 if (ns->prefix != NULL)
1726 cur->prefix = xmlStrdup(ns->prefix);
1727 cur->next = (xmlNsPtr) node;
1728 return((xmlNodePtr) cur);
1729}
1730
1731/**
1732 * xmlXPathNodeSetFreeNs:
1733 * @ns: the XPath namespace node found in a nodeset.
1734 *
William M. Brack08171912003-12-29 02:52:11 +00001735 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001736 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00001737 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001738 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001739void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001740xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1741 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1742 return;
1743
1744 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1745 if (ns->href != NULL)
1746 xmlFree((xmlChar *)ns->href);
1747 if (ns->prefix != NULL)
1748 xmlFree((xmlChar *)ns->prefix);
1749 xmlFree(ns);
1750 }
1751}
1752
1753/**
Owen Taylor3473f882001-02-23 17:55:21 +00001754 * xmlXPathNodeSetCreate:
1755 * @val: an initial xmlNodePtr, or NULL
1756 *
1757 * Create a new xmlNodeSetPtr of type double and of value @val
1758 *
1759 * Returns the newly created object.
1760 */
1761xmlNodeSetPtr
1762xmlXPathNodeSetCreate(xmlNodePtr val) {
1763 xmlNodeSetPtr ret;
1764
1765 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1766 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001767 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001768 return(NULL);
1769 }
1770 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1771 if (val != NULL) {
1772 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1773 sizeof(xmlNodePtr));
1774 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001775 xmlXPathErrMemory(NULL, "creating nodeset\n");
1776 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001777 return(NULL);
1778 }
1779 memset(ret->nodeTab, 0 ,
1780 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1781 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001782 if (val->type == XML_NAMESPACE_DECL) {
1783 xmlNsPtr ns = (xmlNsPtr) val;
1784
1785 ret->nodeTab[ret->nodeNr++] =
1786 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1787 } else
1788 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001789 }
1790 return(ret);
1791}
1792
1793/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001794 * xmlXPathNodeSetContains:
1795 * @cur: the node-set
1796 * @val: the node
1797 *
1798 * checks whether @cur contains @val
1799 *
1800 * Returns true (1) if @cur contains @val, false (0) otherwise
1801 */
1802int
1803xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1804 int i;
1805
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001806 if (val->type == XML_NAMESPACE_DECL) {
1807 for (i = 0; i < cur->nodeNr; i++) {
1808 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1809 xmlNsPtr ns1, ns2;
1810
1811 ns1 = (xmlNsPtr) val;
1812 ns2 = (xmlNsPtr) cur->nodeTab[i];
1813 if (ns1 == ns2)
1814 return(1);
1815 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1816 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1817 return(1);
1818 }
1819 }
1820 } else {
1821 for (i = 0; i < cur->nodeNr; i++) {
1822 if (cur->nodeTab[i] == val)
1823 return(1);
1824 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001825 }
1826 return(0);
1827}
1828
1829/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001830 * xmlXPathNodeSetAddNs:
1831 * @cur: the initial node set
1832 * @node: the hosting node
1833 * @ns: a the namespace node
1834 *
1835 * add a new namespace node to an existing NodeSet
1836 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001837void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001838xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1839 int i;
1840
1841 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1842 (node->type != XML_ELEMENT_NODE))
1843 return;
1844
William M. Brack08171912003-12-29 02:52:11 +00001845 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001846 /*
William M. Brack08171912003-12-29 02:52:11 +00001847 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001848 */
1849 for (i = 0;i < cur->nodeNr;i++) {
1850 if ((cur->nodeTab[i] != NULL) &&
1851 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001852 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001853 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1854 return;
1855 }
1856
1857 /*
1858 * grow the nodeTab if needed
1859 */
1860 if (cur->nodeMax == 0) {
1861 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1862 sizeof(xmlNodePtr));
1863 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001864 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001865 return;
1866 }
1867 memset(cur->nodeTab, 0 ,
1868 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1869 cur->nodeMax = XML_NODESET_DEFAULT;
1870 } else if (cur->nodeNr == cur->nodeMax) {
1871 xmlNodePtr *temp;
1872
1873 cur->nodeMax *= 2;
1874 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1875 sizeof(xmlNodePtr));
1876 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001877 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001878 return;
1879 }
1880 cur->nodeTab = temp;
1881 }
1882 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1883}
1884
1885/**
Owen Taylor3473f882001-02-23 17:55:21 +00001886 * xmlXPathNodeSetAdd:
1887 * @cur: the initial node set
1888 * @val: a new xmlNodePtr
1889 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001890 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001891 */
1892void
1893xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1894 int i;
1895
1896 if (val == NULL) return;
1897
Daniel Veillardef0b4502003-03-24 13:57:34 +00001898#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001899 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1900 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001901#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001902
William M. Brack08171912003-12-29 02:52:11 +00001903 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001904 /*
William M. Brack08171912003-12-29 02:52:11 +00001905 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00001906 */
1907 for (i = 0;i < cur->nodeNr;i++)
1908 if (cur->nodeTab[i] == val) return;
1909
1910 /*
1911 * grow the nodeTab if needed
1912 */
1913 if (cur->nodeMax == 0) {
1914 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1915 sizeof(xmlNodePtr));
1916 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001917 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001918 return;
1919 }
1920 memset(cur->nodeTab, 0 ,
1921 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1922 cur->nodeMax = XML_NODESET_DEFAULT;
1923 } else if (cur->nodeNr == cur->nodeMax) {
1924 xmlNodePtr *temp;
1925
1926 cur->nodeMax *= 2;
1927 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1928 sizeof(xmlNodePtr));
1929 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001930 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001931 return;
1932 }
1933 cur->nodeTab = temp;
1934 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001935 if (val->type == XML_NAMESPACE_DECL) {
1936 xmlNsPtr ns = (xmlNsPtr) val;
1937
1938 cur->nodeTab[cur->nodeNr++] =
1939 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1940 } else
1941 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001942}
1943
1944/**
1945 * xmlXPathNodeSetAddUnique:
1946 * @cur: the initial node set
1947 * @val: a new xmlNodePtr
1948 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001949 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001950 * when we are sure the node is not already in the set.
1951 */
1952void
1953xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1954 if (val == NULL) return;
1955
Daniel Veillardef0b4502003-03-24 13:57:34 +00001956#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001957 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1958 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001959#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001960
William M. Brack08171912003-12-29 02:52:11 +00001961 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001962 /*
1963 * grow the nodeTab if needed
1964 */
1965 if (cur->nodeMax == 0) {
1966 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1967 sizeof(xmlNodePtr));
1968 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001969 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001970 return;
1971 }
1972 memset(cur->nodeTab, 0 ,
1973 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1974 cur->nodeMax = XML_NODESET_DEFAULT;
1975 } else if (cur->nodeNr == cur->nodeMax) {
1976 xmlNodePtr *temp;
1977
1978 cur->nodeMax *= 2;
1979 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1980 sizeof(xmlNodePtr));
1981 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001982 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001983 return;
1984 }
1985 cur->nodeTab = temp;
1986 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001987 if (val->type == XML_NAMESPACE_DECL) {
1988 xmlNsPtr ns = (xmlNsPtr) val;
1989
1990 cur->nodeTab[cur->nodeNr++] =
1991 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1992 } else
1993 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001994}
1995
1996/**
1997 * xmlXPathNodeSetMerge:
1998 * @val1: the first NodeSet or NULL
1999 * @val2: the second NodeSet
2000 *
2001 * Merges two nodesets, all nodes from @val2 are added to @val1
2002 * if @val1 is NULL, a new set is created and copied from @val2
2003 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002004 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002005 */
2006xmlNodeSetPtr
2007xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002008 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00002009
2010 if (val2 == NULL) return(val1);
2011 if (val1 == NULL) {
2012 val1 = xmlXPathNodeSetCreate(NULL);
2013 }
2014
William M. Brack08171912003-12-29 02:52:11 +00002015 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002016 initNr = val1->nodeNr;
2017
2018 for (i = 0;i < val2->nodeNr;i++) {
2019 /*
William M. Brack08171912003-12-29 02:52:11 +00002020 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00002021 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002022 skip = 0;
2023 for (j = 0; j < initNr; j++) {
2024 if (val1->nodeTab[j] == val2->nodeTab[i]) {
2025 skip = 1;
2026 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002027 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
2028 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
2029 xmlNsPtr ns1, ns2;
2030 ns1 = (xmlNsPtr) val1->nodeTab[j];
2031 ns2 = (xmlNsPtr) val2->nodeTab[i];
2032 if ((ns1->next == ns2->next) &&
2033 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
2034 skip = 1;
2035 break;
2036 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002037 }
2038 }
2039 if (skip)
2040 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00002041
2042 /*
2043 * grow the nodeTab if needed
2044 */
2045 if (val1->nodeMax == 0) {
2046 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2047 sizeof(xmlNodePtr));
2048 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002049 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002050 return(NULL);
2051 }
2052 memset(val1->nodeTab, 0 ,
2053 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2054 val1->nodeMax = XML_NODESET_DEFAULT;
2055 } else if (val1->nodeNr == val1->nodeMax) {
2056 xmlNodePtr *temp;
2057
2058 val1->nodeMax *= 2;
2059 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2060 sizeof(xmlNodePtr));
2061 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002062 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002063 return(NULL);
2064 }
2065 val1->nodeTab = temp;
2066 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002067 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2068 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2069
2070 val1->nodeTab[val1->nodeNr++] =
2071 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2072 } else
2073 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002074 }
2075
2076 return(val1);
2077}
2078
2079/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002080 * xmlXPathNodeSetMergeUnique:
2081 * @val1: the first NodeSet or NULL
2082 * @val2: the second NodeSet
2083 *
2084 * Merges two nodesets, all nodes from @val2 are added to @val1
2085 * if @val1 is NULL, a new set is created and copied from @val2
2086 *
2087 * Returns @val1 once extended or NULL in case of error.
2088 */
2089static xmlNodeSetPtr
2090xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002091 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002092
2093 if (val2 == NULL) return(val1);
2094 if (val1 == NULL) {
2095 val1 = xmlXPathNodeSetCreate(NULL);
2096 }
2097
William M. Brack08171912003-12-29 02:52:11 +00002098 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002099
2100 for (i = 0;i < val2->nodeNr;i++) {
2101 /*
2102 * grow the nodeTab if needed
2103 */
2104 if (val1->nodeMax == 0) {
2105 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2106 sizeof(xmlNodePtr));
2107 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002108 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002109 return(NULL);
2110 }
2111 memset(val1->nodeTab, 0 ,
2112 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2113 val1->nodeMax = XML_NODESET_DEFAULT;
2114 } else if (val1->nodeNr == val1->nodeMax) {
2115 xmlNodePtr *temp;
2116
2117 val1->nodeMax *= 2;
2118 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2119 sizeof(xmlNodePtr));
2120 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002121 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002122 return(NULL);
2123 }
2124 val1->nodeTab = temp;
2125 }
2126 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2127 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2128
2129 val1->nodeTab[val1->nodeNr++] =
2130 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2131 } else
2132 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2133 }
2134
2135 return(val1);
2136}
2137
2138/**
Owen Taylor3473f882001-02-23 17:55:21 +00002139 * xmlXPathNodeSetDel:
2140 * @cur: the initial node set
2141 * @val: an xmlNodePtr
2142 *
2143 * Removes an xmlNodePtr from an existing NodeSet
2144 */
2145void
2146xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2147 int i;
2148
2149 if (cur == NULL) return;
2150 if (val == NULL) return;
2151
2152 /*
William M. Brack08171912003-12-29 02:52:11 +00002153 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002154 */
2155 for (i = 0;i < cur->nodeNr;i++)
2156 if (cur->nodeTab[i] == val) break;
2157
William M. Brack08171912003-12-29 02:52:11 +00002158 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002159#ifdef DEBUG
2160 xmlGenericError(xmlGenericErrorContext,
2161 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2162 val->name);
2163#endif
2164 return;
2165 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002166 if ((cur->nodeTab[i] != NULL) &&
2167 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2168 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002169 cur->nodeNr--;
2170 for (;i < cur->nodeNr;i++)
2171 cur->nodeTab[i] = cur->nodeTab[i + 1];
2172 cur->nodeTab[cur->nodeNr] = NULL;
2173}
2174
2175/**
2176 * xmlXPathNodeSetRemove:
2177 * @cur: the initial node set
2178 * @val: the index to remove
2179 *
2180 * Removes an entry from an existing NodeSet list.
2181 */
2182void
2183xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2184 if (cur == NULL) return;
2185 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002186 if ((cur->nodeTab[val] != NULL) &&
2187 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2188 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002189 cur->nodeNr--;
2190 for (;val < cur->nodeNr;val++)
2191 cur->nodeTab[val] = cur->nodeTab[val + 1];
2192 cur->nodeTab[cur->nodeNr] = NULL;
2193}
2194
2195/**
2196 * xmlXPathFreeNodeSet:
2197 * @obj: the xmlNodeSetPtr to free
2198 *
2199 * Free the NodeSet compound (not the actual nodes !).
2200 */
2201void
2202xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2203 if (obj == NULL) return;
2204 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002205 int i;
2206
William M. Brack08171912003-12-29 02:52:11 +00002207 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002208 for (i = 0;i < obj->nodeNr;i++)
2209 if ((obj->nodeTab[i] != NULL) &&
2210 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2211 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002212 xmlFree(obj->nodeTab);
2213 }
Owen Taylor3473f882001-02-23 17:55:21 +00002214 xmlFree(obj);
2215}
2216
2217/**
2218 * xmlXPathFreeValueTree:
2219 * @obj: the xmlNodeSetPtr to free
2220 *
2221 * Free the NodeSet compound and the actual tree, this is different
2222 * from xmlXPathFreeNodeSet()
2223 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002224static void
Owen Taylor3473f882001-02-23 17:55:21 +00002225xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2226 int i;
2227
2228 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002229
2230 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002231 for (i = 0;i < obj->nodeNr;i++) {
2232 if (obj->nodeTab[i] != NULL) {
2233 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2234 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2235 } else {
2236 xmlFreeNodeList(obj->nodeTab[i]);
2237 }
2238 }
2239 }
Owen Taylor3473f882001-02-23 17:55:21 +00002240 xmlFree(obj->nodeTab);
2241 }
Owen Taylor3473f882001-02-23 17:55:21 +00002242 xmlFree(obj);
2243}
2244
2245#if defined(DEBUG) || defined(DEBUG_STEP)
2246/**
2247 * xmlGenericErrorContextNodeSet:
2248 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002249 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002250 *
2251 * Quick display of a NodeSet
2252 */
2253void
2254xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2255 int i;
2256
2257 if (output == NULL) output = xmlGenericErrorContext;
2258 if (obj == NULL) {
2259 fprintf(output, "NodeSet == NULL !\n");
2260 return;
2261 }
2262 if (obj->nodeNr == 0) {
2263 fprintf(output, "NodeSet is empty\n");
2264 return;
2265 }
2266 if (obj->nodeTab == NULL) {
2267 fprintf(output, " nodeTab == NULL !\n");
2268 return;
2269 }
2270 for (i = 0; i < obj->nodeNr; i++) {
2271 if (obj->nodeTab[i] == NULL) {
2272 fprintf(output, " NULL !\n");
2273 return;
2274 }
2275 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2276 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2277 fprintf(output, " /");
2278 else if (obj->nodeTab[i]->name == NULL)
2279 fprintf(output, " noname!");
2280 else fprintf(output, " %s", obj->nodeTab[i]->name);
2281 }
2282 fprintf(output, "\n");
2283}
2284#endif
2285
2286/**
2287 * xmlXPathNewNodeSet:
2288 * @val: the NodePtr value
2289 *
2290 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2291 * it with the single Node @val
2292 *
2293 * Returns the newly created object.
2294 */
2295xmlXPathObjectPtr
2296xmlXPathNewNodeSet(xmlNodePtr val) {
2297 xmlXPathObjectPtr ret;
2298
2299 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2300 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002301 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002302 return(NULL);
2303 }
2304 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2305 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002306 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002307 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002308 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002309 return(ret);
2310}
2311
2312/**
2313 * xmlXPathNewValueTree:
2314 * @val: the NodePtr value
2315 *
2316 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2317 * it with the tree root @val
2318 *
2319 * Returns the newly created object.
2320 */
2321xmlXPathObjectPtr
2322xmlXPathNewValueTree(xmlNodePtr val) {
2323 xmlXPathObjectPtr ret;
2324
2325 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2326 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002327 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002328 return(NULL);
2329 }
2330 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2331 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002332 ret->boolval = 1;
2333 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002334 ret->nodesetval = xmlXPathNodeSetCreate(val);
2335 return(ret);
2336}
2337
2338/**
2339 * xmlXPathNewNodeSetList:
2340 * @val: an existing NodeSet
2341 *
2342 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2343 * it with the Nodeset @val
2344 *
2345 * Returns the newly created object.
2346 */
2347xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002348xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2349{
Owen Taylor3473f882001-02-23 17:55:21 +00002350 xmlXPathObjectPtr ret;
2351 int i;
2352
2353 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002354 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002355 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002356 ret = xmlXPathNewNodeSet(NULL);
2357 else {
2358 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2359 for (i = 1; i < val->nodeNr; ++i)
2360 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2361 }
Owen Taylor3473f882001-02-23 17:55:21 +00002362
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002363 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002364}
2365
2366/**
2367 * xmlXPathWrapNodeSet:
2368 * @val: the NodePtr value
2369 *
2370 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2371 *
2372 * Returns the newly created object.
2373 */
2374xmlXPathObjectPtr
2375xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2376 xmlXPathObjectPtr ret;
2377
2378 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2379 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002380 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002381 return(NULL);
2382 }
2383 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2384 ret->type = XPATH_NODESET;
2385 ret->nodesetval = val;
2386 return(ret);
2387}
2388
2389/**
2390 * xmlXPathFreeNodeSetList:
2391 * @obj: an existing NodeSetList object
2392 *
2393 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2394 * the list contrary to xmlXPathFreeObject().
2395 */
2396void
2397xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2398 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002399 xmlFree(obj);
2400}
2401
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002402/**
2403 * xmlXPathDifference:
2404 * @nodes1: a node-set
2405 * @nodes2: a node-set
2406 *
2407 * Implements the EXSLT - Sets difference() function:
2408 * node-set set:difference (node-set, node-set)
2409 *
2410 * Returns the difference between the two node sets, or nodes1 if
2411 * nodes2 is empty
2412 */
2413xmlNodeSetPtr
2414xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2415 xmlNodeSetPtr ret;
2416 int i, l1;
2417 xmlNodePtr cur;
2418
2419 if (xmlXPathNodeSetIsEmpty(nodes2))
2420 return(nodes1);
2421
2422 ret = xmlXPathNodeSetCreate(NULL);
2423 if (xmlXPathNodeSetIsEmpty(nodes1))
2424 return(ret);
2425
2426 l1 = xmlXPathNodeSetGetLength(nodes1);
2427
2428 for (i = 0; i < l1; i++) {
2429 cur = xmlXPathNodeSetItem(nodes1, i);
2430 if (!xmlXPathNodeSetContains(nodes2, cur))
2431 xmlXPathNodeSetAddUnique(ret, cur);
2432 }
2433 return(ret);
2434}
2435
2436/**
2437 * xmlXPathIntersection:
2438 * @nodes1: a node-set
2439 * @nodes2: a node-set
2440 *
2441 * Implements the EXSLT - Sets intersection() function:
2442 * node-set set:intersection (node-set, node-set)
2443 *
2444 * Returns a node set comprising the nodes that are within both the
2445 * node sets passed as arguments
2446 */
2447xmlNodeSetPtr
2448xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2449 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2450 int i, l1;
2451 xmlNodePtr cur;
2452
2453 if (xmlXPathNodeSetIsEmpty(nodes1))
2454 return(ret);
2455 if (xmlXPathNodeSetIsEmpty(nodes2))
2456 return(ret);
2457
2458 l1 = xmlXPathNodeSetGetLength(nodes1);
2459
2460 for (i = 0; i < l1; i++) {
2461 cur = xmlXPathNodeSetItem(nodes1, i);
2462 if (xmlXPathNodeSetContains(nodes2, cur))
2463 xmlXPathNodeSetAddUnique(ret, cur);
2464 }
2465 return(ret);
2466}
2467
2468/**
2469 * xmlXPathDistinctSorted:
2470 * @nodes: a node-set, sorted by document order
2471 *
2472 * Implements the EXSLT - Sets distinct() function:
2473 * node-set set:distinct (node-set)
2474 *
2475 * Returns a subset of the nodes contained in @nodes, or @nodes if
2476 * it is empty
2477 */
2478xmlNodeSetPtr
2479xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2480 xmlNodeSetPtr ret;
2481 xmlHashTablePtr hash;
2482 int i, l;
2483 xmlChar * strval;
2484 xmlNodePtr cur;
2485
2486 if (xmlXPathNodeSetIsEmpty(nodes))
2487 return(nodes);
2488
2489 ret = xmlXPathNodeSetCreate(NULL);
2490 l = xmlXPathNodeSetGetLength(nodes);
2491 hash = xmlHashCreate (l);
2492 for (i = 0; i < l; i++) {
2493 cur = xmlXPathNodeSetItem(nodes, i);
2494 strval = xmlXPathCastNodeToString(cur);
2495 if (xmlHashLookup(hash, strval) == NULL) {
2496 xmlHashAddEntry(hash, strval, strval);
2497 xmlXPathNodeSetAddUnique(ret, cur);
2498 } else {
2499 xmlFree(strval);
2500 }
2501 }
2502 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2503 return(ret);
2504}
2505
2506/**
2507 * xmlXPathDistinct:
2508 * @nodes: a node-set
2509 *
2510 * Implements the EXSLT - Sets distinct() function:
2511 * node-set set:distinct (node-set)
2512 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2513 * is called with the sorted node-set
2514 *
2515 * Returns a subset of the nodes contained in @nodes, or @nodes if
2516 * it is empty
2517 */
2518xmlNodeSetPtr
2519xmlXPathDistinct (xmlNodeSetPtr nodes) {
2520 if (xmlXPathNodeSetIsEmpty(nodes))
2521 return(nodes);
2522
2523 xmlXPathNodeSetSort(nodes);
2524 return(xmlXPathDistinctSorted(nodes));
2525}
2526
2527/**
2528 * xmlXPathHasSameNodes:
2529 * @nodes1: a node-set
2530 * @nodes2: a node-set
2531 *
2532 * Implements the EXSLT - Sets has-same-nodes function:
2533 * boolean set:has-same-node(node-set, node-set)
2534 *
2535 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2536 * otherwise
2537 */
2538int
2539xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2540 int i, l;
2541 xmlNodePtr cur;
2542
2543 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2544 xmlXPathNodeSetIsEmpty(nodes2))
2545 return(0);
2546
2547 l = xmlXPathNodeSetGetLength(nodes1);
2548 for (i = 0; i < l; i++) {
2549 cur = xmlXPathNodeSetItem(nodes1, i);
2550 if (xmlXPathNodeSetContains(nodes2, cur))
2551 return(1);
2552 }
2553 return(0);
2554}
2555
2556/**
2557 * xmlXPathNodeLeadingSorted:
2558 * @nodes: a node-set, sorted by document order
2559 * @node: a node
2560 *
2561 * Implements the EXSLT - Sets leading() function:
2562 * node-set set:leading (node-set, node-set)
2563 *
2564 * Returns the nodes in @nodes that precede @node in document order,
2565 * @nodes if @node is NULL or an empty node-set if @nodes
2566 * doesn't contain @node
2567 */
2568xmlNodeSetPtr
2569xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2570 int i, l;
2571 xmlNodePtr cur;
2572 xmlNodeSetPtr ret;
2573
2574 if (node == NULL)
2575 return(nodes);
2576
2577 ret = xmlXPathNodeSetCreate(NULL);
2578 if (xmlXPathNodeSetIsEmpty(nodes) ||
2579 (!xmlXPathNodeSetContains(nodes, node)))
2580 return(ret);
2581
2582 l = xmlXPathNodeSetGetLength(nodes);
2583 for (i = 0; i < l; i++) {
2584 cur = xmlXPathNodeSetItem(nodes, i);
2585 if (cur == node)
2586 break;
2587 xmlXPathNodeSetAddUnique(ret, cur);
2588 }
2589 return(ret);
2590}
2591
2592/**
2593 * xmlXPathNodeLeading:
2594 * @nodes: a node-set
2595 * @node: a node
2596 *
2597 * Implements the EXSLT - Sets leading() function:
2598 * node-set set:leading (node-set, node-set)
2599 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2600 * is called.
2601 *
2602 * Returns the nodes in @nodes that precede @node in document order,
2603 * @nodes if @node is NULL or an empty node-set if @nodes
2604 * doesn't contain @node
2605 */
2606xmlNodeSetPtr
2607xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2608 xmlXPathNodeSetSort(nodes);
2609 return(xmlXPathNodeLeadingSorted(nodes, node));
2610}
2611
2612/**
2613 * xmlXPathLeadingSorted:
2614 * @nodes1: a node-set, sorted by document order
2615 * @nodes2: a node-set, sorted by document order
2616 *
2617 * Implements the EXSLT - Sets leading() function:
2618 * node-set set:leading (node-set, node-set)
2619 *
2620 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2621 * in document order, @nodes1 if @nodes2 is NULL or empty or
2622 * an empty node-set if @nodes1 doesn't contain @nodes2
2623 */
2624xmlNodeSetPtr
2625xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2626 if (xmlXPathNodeSetIsEmpty(nodes2))
2627 return(nodes1);
2628 return(xmlXPathNodeLeadingSorted(nodes1,
2629 xmlXPathNodeSetItem(nodes2, 1)));
2630}
2631
2632/**
2633 * xmlXPathLeading:
2634 * @nodes1: a node-set
2635 * @nodes2: a node-set
2636 *
2637 * Implements the EXSLT - Sets leading() function:
2638 * node-set set:leading (node-set, node-set)
2639 * @nodes1 and @nodes2 are sorted by document order, then
2640 * #exslSetsLeadingSorted is called.
2641 *
2642 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2643 * in document order, @nodes1 if @nodes2 is NULL or empty or
2644 * an empty node-set if @nodes1 doesn't contain @nodes2
2645 */
2646xmlNodeSetPtr
2647xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2648 if (xmlXPathNodeSetIsEmpty(nodes2))
2649 return(nodes1);
2650 if (xmlXPathNodeSetIsEmpty(nodes1))
2651 return(xmlXPathNodeSetCreate(NULL));
2652 xmlXPathNodeSetSort(nodes1);
2653 xmlXPathNodeSetSort(nodes2);
2654 return(xmlXPathNodeLeadingSorted(nodes1,
2655 xmlXPathNodeSetItem(nodes2, 1)));
2656}
2657
2658/**
2659 * xmlXPathNodeTrailingSorted:
2660 * @nodes: a node-set, sorted by document order
2661 * @node: a node
2662 *
2663 * Implements the EXSLT - Sets trailing() function:
2664 * node-set set:trailing (node-set, node-set)
2665 *
2666 * Returns the nodes in @nodes that follow @node in document order,
2667 * @nodes if @node is NULL or an empty node-set if @nodes
2668 * doesn't contain @node
2669 */
2670xmlNodeSetPtr
2671xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2672 int i, l;
2673 xmlNodePtr cur;
2674 xmlNodeSetPtr ret;
2675
2676 if (node == NULL)
2677 return(nodes);
2678
2679 ret = xmlXPathNodeSetCreate(NULL);
2680 if (xmlXPathNodeSetIsEmpty(nodes) ||
2681 (!xmlXPathNodeSetContains(nodes, node)))
2682 return(ret);
2683
2684 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002685 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002686 cur = xmlXPathNodeSetItem(nodes, i);
2687 if (cur == node)
2688 break;
2689 xmlXPathNodeSetAddUnique(ret, cur);
2690 }
2691 return(ret);
2692}
2693
2694/**
2695 * xmlXPathNodeTrailing:
2696 * @nodes: a node-set
2697 * @node: a node
2698 *
2699 * Implements the EXSLT - Sets trailing() function:
2700 * node-set set:trailing (node-set, node-set)
2701 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2702 * is called.
2703 *
2704 * Returns the nodes in @nodes that follow @node in document order,
2705 * @nodes if @node is NULL or an empty node-set if @nodes
2706 * doesn't contain @node
2707 */
2708xmlNodeSetPtr
2709xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2710 xmlXPathNodeSetSort(nodes);
2711 return(xmlXPathNodeTrailingSorted(nodes, node));
2712}
2713
2714/**
2715 * xmlXPathTrailingSorted:
2716 * @nodes1: a node-set, sorted by document order
2717 * @nodes2: a node-set, sorted by document order
2718 *
2719 * Implements the EXSLT - Sets trailing() function:
2720 * node-set set:trailing (node-set, node-set)
2721 *
2722 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2723 * in document order, @nodes1 if @nodes2 is NULL or empty or
2724 * an empty node-set if @nodes1 doesn't contain @nodes2
2725 */
2726xmlNodeSetPtr
2727xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2728 if (xmlXPathNodeSetIsEmpty(nodes2))
2729 return(nodes1);
2730 return(xmlXPathNodeTrailingSorted(nodes1,
2731 xmlXPathNodeSetItem(nodes2, 0)));
2732}
2733
2734/**
2735 * xmlXPathTrailing:
2736 * @nodes1: a node-set
2737 * @nodes2: a node-set
2738 *
2739 * Implements the EXSLT - Sets trailing() function:
2740 * node-set set:trailing (node-set, node-set)
2741 * @nodes1 and @nodes2 are sorted by document order, then
2742 * #xmlXPathTrailingSorted is called.
2743 *
2744 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2745 * in document order, @nodes1 if @nodes2 is NULL or empty or
2746 * an empty node-set if @nodes1 doesn't contain @nodes2
2747 */
2748xmlNodeSetPtr
2749xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2750 if (xmlXPathNodeSetIsEmpty(nodes2))
2751 return(nodes1);
2752 if (xmlXPathNodeSetIsEmpty(nodes1))
2753 return(xmlXPathNodeSetCreate(NULL));
2754 xmlXPathNodeSetSort(nodes1);
2755 xmlXPathNodeSetSort(nodes2);
2756 return(xmlXPathNodeTrailingSorted(nodes1,
2757 xmlXPathNodeSetItem(nodes2, 0)));
2758}
2759
Owen Taylor3473f882001-02-23 17:55:21 +00002760/************************************************************************
2761 * *
2762 * Routines to handle extra functions *
2763 * *
2764 ************************************************************************/
2765
2766/**
2767 * xmlXPathRegisterFunc:
2768 * @ctxt: the XPath context
2769 * @name: the function name
2770 * @f: the function implementation or NULL
2771 *
2772 * Register a new function. If @f is NULL it unregisters the function
2773 *
2774 * Returns 0 in case of success, -1 in case of error
2775 */
2776int
2777xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2778 xmlXPathFunction f) {
2779 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2780}
2781
2782/**
2783 * xmlXPathRegisterFuncNS:
2784 * @ctxt: the XPath context
2785 * @name: the function name
2786 * @ns_uri: the function namespace URI
2787 * @f: the function implementation or NULL
2788 *
2789 * Register a new function. If @f is NULL it unregisters the function
2790 *
2791 * Returns 0 in case of success, -1 in case of error
2792 */
2793int
2794xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2795 const xmlChar *ns_uri, xmlXPathFunction f) {
2796 if (ctxt == NULL)
2797 return(-1);
2798 if (name == NULL)
2799 return(-1);
2800
2801 if (ctxt->funcHash == NULL)
2802 ctxt->funcHash = xmlHashCreate(0);
2803 if (ctxt->funcHash == NULL)
2804 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002805 if (f == NULL)
2806 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
Owen Taylor3473f882001-02-23 17:55:21 +00002807 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2808}
2809
2810/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002811 * xmlXPathRegisterFuncLookup:
2812 * @ctxt: the XPath context
2813 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002814 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002815 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002816 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002817 */
2818void
2819xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2820 xmlXPathFuncLookupFunc f,
2821 void *funcCtxt) {
2822 if (ctxt == NULL)
2823 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002824 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002825 ctxt->funcLookupData = funcCtxt;
2826}
2827
2828/**
Owen Taylor3473f882001-02-23 17:55:21 +00002829 * xmlXPathFunctionLookup:
2830 * @ctxt: the XPath context
2831 * @name: the function name
2832 *
2833 * Search in the Function array of the context for the given
2834 * function.
2835 *
2836 * Returns the xmlXPathFunction or NULL if not found
2837 */
2838xmlXPathFunction
2839xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002840 if (ctxt == NULL)
2841 return (NULL);
2842
2843 if (ctxt->funcLookupFunc != NULL) {
2844 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002845 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002846
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002847 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002848 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002849 if (ret != NULL)
2850 return(ret);
2851 }
Owen Taylor3473f882001-02-23 17:55:21 +00002852 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2853}
2854
2855/**
2856 * xmlXPathFunctionLookupNS:
2857 * @ctxt: the XPath context
2858 * @name: the function name
2859 * @ns_uri: the function namespace URI
2860 *
2861 * Search in the Function array of the context for the given
2862 * function.
2863 *
2864 * Returns the xmlXPathFunction or NULL if not found
2865 */
2866xmlXPathFunction
2867xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2868 const xmlChar *ns_uri) {
2869 if (ctxt == NULL)
2870 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002871 if (name == NULL)
2872 return(NULL);
2873
Thomas Broyerba4ad322001-07-26 16:55:21 +00002874 if (ctxt->funcLookupFunc != NULL) {
2875 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002876 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002877
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002878 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002879 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002880 if (ret != NULL)
2881 return(ret);
2882 }
2883
2884 if (ctxt->funcHash == NULL)
2885 return(NULL);
2886
Owen Taylor3473f882001-02-23 17:55:21 +00002887 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2888}
2889
2890/**
2891 * xmlXPathRegisteredFuncsCleanup:
2892 * @ctxt: the XPath context
2893 *
2894 * Cleanup the XPath context data associated to registered functions
2895 */
2896void
2897xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2898 if (ctxt == NULL)
2899 return;
2900
2901 xmlHashFree(ctxt->funcHash, NULL);
2902 ctxt->funcHash = NULL;
2903}
2904
2905/************************************************************************
2906 * *
William M. Brack08171912003-12-29 02:52:11 +00002907 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00002908 * *
2909 ************************************************************************/
2910
2911/**
2912 * xmlXPathRegisterVariable:
2913 * @ctxt: the XPath context
2914 * @name: the variable name
2915 * @value: the variable value or NULL
2916 *
2917 * Register a new variable value. If @value is NULL it unregisters
2918 * the variable
2919 *
2920 * Returns 0 in case of success, -1 in case of error
2921 */
2922int
2923xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2924 xmlXPathObjectPtr value) {
2925 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2926}
2927
2928/**
2929 * xmlXPathRegisterVariableNS:
2930 * @ctxt: the XPath context
2931 * @name: the variable name
2932 * @ns_uri: the variable namespace URI
2933 * @value: the variable value or NULL
2934 *
2935 * Register a new variable value. If @value is NULL it unregisters
2936 * the variable
2937 *
2938 * Returns 0 in case of success, -1 in case of error
2939 */
2940int
2941xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2942 const xmlChar *ns_uri,
2943 xmlXPathObjectPtr value) {
2944 if (ctxt == NULL)
2945 return(-1);
2946 if (name == NULL)
2947 return(-1);
2948
2949 if (ctxt->varHash == NULL)
2950 ctxt->varHash = xmlHashCreate(0);
2951 if (ctxt->varHash == NULL)
2952 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002953 if (value == NULL)
2954 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2955 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002956 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2957 (void *) value,
2958 (xmlHashDeallocator)xmlXPathFreeObject));
2959}
2960
2961/**
2962 * xmlXPathRegisterVariableLookup:
2963 * @ctxt: the XPath context
2964 * @f: the lookup function
2965 * @data: the lookup data
2966 *
2967 * register an external mechanism to do variable lookup
2968 */
2969void
2970xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2971 xmlXPathVariableLookupFunc f, void *data) {
2972 if (ctxt == NULL)
2973 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002974 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00002975 ctxt->varLookupData = data;
2976}
2977
2978/**
2979 * xmlXPathVariableLookup:
2980 * @ctxt: the XPath context
2981 * @name: the variable name
2982 *
2983 * Search in the Variable array of the context for the given
2984 * variable value.
2985 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002986 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002987 */
2988xmlXPathObjectPtr
2989xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2990 if (ctxt == NULL)
2991 return(NULL);
2992
2993 if (ctxt->varLookupFunc != NULL) {
2994 xmlXPathObjectPtr ret;
2995
2996 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2997 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002998 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002999 }
3000 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3001}
3002
3003/**
3004 * xmlXPathVariableLookupNS:
3005 * @ctxt: the XPath context
3006 * @name: the variable name
3007 * @ns_uri: the variable namespace URI
3008 *
3009 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00003010 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00003011 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003012 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003013 */
3014xmlXPathObjectPtr
3015xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3016 const xmlChar *ns_uri) {
3017 if (ctxt == NULL)
3018 return(NULL);
3019
3020 if (ctxt->varLookupFunc != NULL) {
3021 xmlXPathObjectPtr ret;
3022
3023 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3024 (ctxt->varLookupData, name, ns_uri);
3025 if (ret != NULL) return(ret);
3026 }
3027
3028 if (ctxt->varHash == NULL)
3029 return(NULL);
3030 if (name == NULL)
3031 return(NULL);
3032
Daniel Veillard8c357d52001-07-03 23:43:33 +00003033 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3034 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00003035}
3036
3037/**
3038 * xmlXPathRegisteredVariablesCleanup:
3039 * @ctxt: the XPath context
3040 *
3041 * Cleanup the XPath context data associated to registered variables
3042 */
3043void
3044xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3045 if (ctxt == NULL)
3046 return;
3047
Daniel Veillard76d66f42001-05-16 21:05:17 +00003048 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00003049 ctxt->varHash = NULL;
3050}
3051
3052/**
3053 * xmlXPathRegisterNs:
3054 * @ctxt: the XPath context
3055 * @prefix: the namespace prefix
3056 * @ns_uri: the namespace name
3057 *
3058 * Register a new namespace. If @ns_uri is NULL it unregisters
3059 * the namespace
3060 *
3061 * Returns 0 in case of success, -1 in case of error
3062 */
3063int
3064xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3065 const xmlChar *ns_uri) {
3066 if (ctxt == NULL)
3067 return(-1);
3068 if (prefix == NULL)
3069 return(-1);
3070
3071 if (ctxt->nsHash == NULL)
3072 ctxt->nsHash = xmlHashCreate(10);
3073 if (ctxt->nsHash == NULL)
3074 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003075 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003076 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003077 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003078 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003079 (xmlHashDeallocator)xmlFree));
3080}
3081
3082/**
3083 * xmlXPathNsLookup:
3084 * @ctxt: the XPath context
3085 * @prefix: the namespace prefix value
3086 *
3087 * Search in the namespace declaration array of the context for the given
3088 * namespace name associated to the given prefix
3089 *
3090 * Returns the value or NULL if not found
3091 */
3092const xmlChar *
3093xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3094 if (ctxt == NULL)
3095 return(NULL);
3096 if (prefix == NULL)
3097 return(NULL);
3098
3099#ifdef XML_XML_NAMESPACE
3100 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3101 return(XML_XML_NAMESPACE);
3102#endif
3103
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003104 if (ctxt->namespaces != NULL) {
3105 int i;
3106
3107 for (i = 0;i < ctxt->nsNr;i++) {
3108 if ((ctxt->namespaces[i] != NULL) &&
3109 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3110 return(ctxt->namespaces[i]->href);
3111 }
3112 }
Owen Taylor3473f882001-02-23 17:55:21 +00003113
3114 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3115}
3116
3117/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003118 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003119 * @ctxt: the XPath context
3120 *
3121 * Cleanup the XPath context data associated to registered variables
3122 */
3123void
3124xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3125 if (ctxt == NULL)
3126 return;
3127
Daniel Veillard42766c02002-08-22 20:52:17 +00003128 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003129 ctxt->nsHash = NULL;
3130}
3131
3132/************************************************************************
3133 * *
3134 * Routines to handle Values *
3135 * *
3136 ************************************************************************/
3137
William M. Brack08171912003-12-29 02:52:11 +00003138/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003139
3140/**
3141 * xmlXPathNewFloat:
3142 * @val: the double value
3143 *
3144 * Create a new xmlXPathObjectPtr of type double and of value @val
3145 *
3146 * Returns the newly created object.
3147 */
3148xmlXPathObjectPtr
3149xmlXPathNewFloat(double val) {
3150 xmlXPathObjectPtr ret;
3151
3152 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3153 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003154 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003155 return(NULL);
3156 }
3157 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3158 ret->type = XPATH_NUMBER;
3159 ret->floatval = val;
3160 return(ret);
3161}
3162
3163/**
3164 * xmlXPathNewBoolean:
3165 * @val: the boolean value
3166 *
3167 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3168 *
3169 * Returns the newly created object.
3170 */
3171xmlXPathObjectPtr
3172xmlXPathNewBoolean(int val) {
3173 xmlXPathObjectPtr ret;
3174
3175 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3176 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003177 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003178 return(NULL);
3179 }
3180 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3181 ret->type = XPATH_BOOLEAN;
3182 ret->boolval = (val != 0);
3183 return(ret);
3184}
3185
3186/**
3187 * xmlXPathNewString:
3188 * @val: the xmlChar * value
3189 *
3190 * Create a new xmlXPathObjectPtr of type string and of value @val
3191 *
3192 * Returns the newly created object.
3193 */
3194xmlXPathObjectPtr
3195xmlXPathNewString(const xmlChar *val) {
3196 xmlXPathObjectPtr ret;
3197
3198 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3199 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003200 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003201 return(NULL);
3202 }
3203 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3204 ret->type = XPATH_STRING;
3205 if (val != NULL)
3206 ret->stringval = xmlStrdup(val);
3207 else
3208 ret->stringval = xmlStrdup((const xmlChar *)"");
3209 return(ret);
3210}
3211
3212/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003213 * xmlXPathWrapString:
3214 * @val: the xmlChar * value
3215 *
3216 * Wraps the @val string into an XPath object.
3217 *
3218 * Returns the newly created object.
3219 */
3220xmlXPathObjectPtr
3221xmlXPathWrapString (xmlChar *val) {
3222 xmlXPathObjectPtr ret;
3223
3224 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3225 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003226 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003227 return(NULL);
3228 }
3229 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3230 ret->type = XPATH_STRING;
3231 ret->stringval = val;
3232 return(ret);
3233}
3234
3235/**
Owen Taylor3473f882001-02-23 17:55:21 +00003236 * xmlXPathNewCString:
3237 * @val: the char * value
3238 *
3239 * Create a new xmlXPathObjectPtr of type string and of value @val
3240 *
3241 * Returns the newly created object.
3242 */
3243xmlXPathObjectPtr
3244xmlXPathNewCString(const char *val) {
3245 xmlXPathObjectPtr ret;
3246
3247 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3248 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003249 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003250 return(NULL);
3251 }
3252 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3253 ret->type = XPATH_STRING;
3254 ret->stringval = xmlStrdup(BAD_CAST val);
3255 return(ret);
3256}
3257
3258/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003259 * xmlXPathWrapCString:
3260 * @val: the char * value
3261 *
3262 * Wraps a string into an XPath object.
3263 *
3264 * Returns the newly created object.
3265 */
3266xmlXPathObjectPtr
3267xmlXPathWrapCString (char * val) {
3268 return(xmlXPathWrapString((xmlChar *)(val)));
3269}
3270
3271/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003272 * xmlXPathWrapExternal:
3273 * @val: the user data
3274 *
3275 * Wraps the @val data into an XPath object.
3276 *
3277 * Returns the newly created object.
3278 */
3279xmlXPathObjectPtr
3280xmlXPathWrapExternal (void *val) {
3281 xmlXPathObjectPtr ret;
3282
3283 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3284 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003285 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003286 return(NULL);
3287 }
3288 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3289 ret->type = XPATH_USERS;
3290 ret->user = val;
3291 return(ret);
3292}
3293
3294/**
Owen Taylor3473f882001-02-23 17:55:21 +00003295 * xmlXPathObjectCopy:
3296 * @val: the original object
3297 *
3298 * allocate a new copy of a given object
3299 *
3300 * Returns the newly created object.
3301 */
3302xmlXPathObjectPtr
3303xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3304 xmlXPathObjectPtr ret;
3305
3306 if (val == NULL)
3307 return(NULL);
3308
3309 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3310 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003311 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003312 return(NULL);
3313 }
3314 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3315 switch (val->type) {
3316 case XPATH_BOOLEAN:
3317 case XPATH_NUMBER:
3318 case XPATH_POINT:
3319 case XPATH_RANGE:
3320 break;
3321 case XPATH_STRING:
3322 ret->stringval = xmlStrdup(val->stringval);
3323 break;
3324 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00003325#if 0
3326/*
3327 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
3328 this previous handling is no longer correct, and can cause some serious
3329 problems (ref. bug 145547)
3330*/
Owen Taylor3473f882001-02-23 17:55:21 +00003331 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003332 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003333 xmlNodePtr cur, tmp;
3334 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003335
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003336 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003337 top = xmlNewDoc(NULL);
3338 top->name = (char *)
3339 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003340 ret->user = top;
3341 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003342 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003343 cur = val->nodesetval->nodeTab[0]->children;
3344 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003345 tmp = xmlDocCopyNode(cur, top, 1);
3346 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003347 cur = cur->next;
3348 }
3349 }
William M. Bracke9449c52004-07-11 14:41:20 +00003350
Daniel Veillard9adc0462003-03-24 18:39:54 +00003351 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003352 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003353 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003354 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003355 break;
William M. Bracke9449c52004-07-11 14:41:20 +00003356#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003357 case XPATH_NODESET:
3358 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003359 /* Do not deallocate the copied tree value */
3360 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003361 break;
3362 case XPATH_LOCATIONSET:
3363#ifdef LIBXML_XPTR_ENABLED
3364 {
3365 xmlLocationSetPtr loc = val->user;
3366 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3367 break;
3368 }
3369#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003370 case XPATH_USERS:
3371 ret->user = val->user;
3372 break;
3373 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003374 xmlGenericError(xmlGenericErrorContext,
3375 "xmlXPathObjectCopy: unsupported type %d\n",
3376 val->type);
3377 break;
3378 }
3379 return(ret);
3380}
3381
3382/**
3383 * xmlXPathFreeObject:
3384 * @obj: the object to free
3385 *
3386 * Free up an xmlXPathObjectPtr object.
3387 */
3388void
3389xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3390 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003391 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003392 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00003393#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003394 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003395 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003396 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003397 } else
3398#endif
3399 if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003400 xmlXPathFreeValueTree(obj->nodesetval);
3401 } else {
3402 if (obj->nodesetval != NULL)
3403 xmlXPathFreeNodeSet(obj->nodesetval);
3404 }
Owen Taylor3473f882001-02-23 17:55:21 +00003405#ifdef LIBXML_XPTR_ENABLED
3406 } else if (obj->type == XPATH_LOCATIONSET) {
3407 if (obj->user != NULL)
3408 xmlXPtrFreeLocationSet(obj->user);
3409#endif
3410 } else if (obj->type == XPATH_STRING) {
3411 if (obj->stringval != NULL)
3412 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003413 }
3414
Owen Taylor3473f882001-02-23 17:55:21 +00003415 xmlFree(obj);
3416}
3417
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003418
3419/************************************************************************
3420 * *
3421 * Type Casting Routines *
3422 * *
3423 ************************************************************************/
3424
3425/**
3426 * xmlXPathCastBooleanToString:
3427 * @val: a boolean
3428 *
3429 * Converts a boolean to its string value.
3430 *
3431 * Returns a newly allocated string.
3432 */
3433xmlChar *
3434xmlXPathCastBooleanToString (int val) {
3435 xmlChar *ret;
3436 if (val)
3437 ret = xmlStrdup((const xmlChar *) "true");
3438 else
3439 ret = xmlStrdup((const xmlChar *) "false");
3440 return(ret);
3441}
3442
3443/**
3444 * xmlXPathCastNumberToString:
3445 * @val: a number
3446 *
3447 * Converts a number to its string value.
3448 *
3449 * Returns a newly allocated string.
3450 */
3451xmlChar *
3452xmlXPathCastNumberToString (double val) {
3453 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003454 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003455 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003456 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003457 break;
3458 case -1:
3459 ret = xmlStrdup((const xmlChar *) "-Infinity");
3460 break;
3461 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003462 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003463 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003464 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3465 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003466 } else {
3467 /* could be improved */
3468 char buf[100];
3469 xmlXPathFormatNumber(val, buf, 100);
3470 ret = xmlStrdup((const xmlChar *) buf);
3471 }
3472 }
3473 return(ret);
3474}
3475
3476/**
3477 * xmlXPathCastNodeToString:
3478 * @node: a node
3479 *
3480 * Converts a node to its string value.
3481 *
3482 * Returns a newly allocated string.
3483 */
3484xmlChar *
3485xmlXPathCastNodeToString (xmlNodePtr node) {
3486 return(xmlNodeGetContent(node));
3487}
3488
3489/**
3490 * xmlXPathCastNodeSetToString:
3491 * @ns: a node-set
3492 *
3493 * Converts a node-set to its string value.
3494 *
3495 * Returns a newly allocated string.
3496 */
3497xmlChar *
3498xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3499 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3500 return(xmlStrdup((const xmlChar *) ""));
3501
3502 xmlXPathNodeSetSort(ns);
3503 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3504}
3505
3506/**
3507 * xmlXPathCastToString:
3508 * @val: an XPath object
3509 *
3510 * Converts an existing object to its string() equivalent
3511 *
3512 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003513 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003514 * string object).
3515 */
3516xmlChar *
3517xmlXPathCastToString(xmlXPathObjectPtr val) {
3518 xmlChar *ret = NULL;
3519
3520 if (val == NULL)
3521 return(xmlStrdup((const xmlChar *) ""));
3522 switch (val->type) {
3523 case XPATH_UNDEFINED:
3524#ifdef DEBUG_EXPR
3525 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3526#endif
3527 ret = xmlStrdup((const xmlChar *) "");
3528 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003529 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003530 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003531 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3532 break;
3533 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003534 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003535 case XPATH_BOOLEAN:
3536 ret = xmlXPathCastBooleanToString(val->boolval);
3537 break;
3538 case XPATH_NUMBER: {
3539 ret = xmlXPathCastNumberToString(val->floatval);
3540 break;
3541 }
3542 case XPATH_USERS:
3543 case XPATH_POINT:
3544 case XPATH_RANGE:
3545 case XPATH_LOCATIONSET:
3546 TODO
3547 ret = xmlStrdup((const xmlChar *) "");
3548 break;
3549 }
3550 return(ret);
3551}
3552
3553/**
3554 * xmlXPathConvertString:
3555 * @val: an XPath object
3556 *
3557 * Converts an existing object to its string() equivalent
3558 *
3559 * Returns the new object, the old one is freed (or the operation
3560 * is done directly on @val)
3561 */
3562xmlXPathObjectPtr
3563xmlXPathConvertString(xmlXPathObjectPtr val) {
3564 xmlChar *res = NULL;
3565
3566 if (val == NULL)
3567 return(xmlXPathNewCString(""));
3568
3569 switch (val->type) {
3570 case XPATH_UNDEFINED:
3571#ifdef DEBUG_EXPR
3572 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3573#endif
3574 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003575 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003576 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003577 res = xmlXPathCastNodeSetToString(val->nodesetval);
3578 break;
3579 case XPATH_STRING:
3580 return(val);
3581 case XPATH_BOOLEAN:
3582 res = xmlXPathCastBooleanToString(val->boolval);
3583 break;
3584 case XPATH_NUMBER:
3585 res = xmlXPathCastNumberToString(val->floatval);
3586 break;
3587 case XPATH_USERS:
3588 case XPATH_POINT:
3589 case XPATH_RANGE:
3590 case XPATH_LOCATIONSET:
3591 TODO;
3592 break;
3593 }
3594 xmlXPathFreeObject(val);
3595 if (res == NULL)
3596 return(xmlXPathNewCString(""));
3597 return(xmlXPathWrapString(res));
3598}
3599
3600/**
3601 * xmlXPathCastBooleanToNumber:
3602 * @val: a boolean
3603 *
3604 * Converts a boolean to its number value
3605 *
3606 * Returns the number value
3607 */
3608double
3609xmlXPathCastBooleanToNumber(int val) {
3610 if (val)
3611 return(1.0);
3612 return(0.0);
3613}
3614
3615/**
3616 * xmlXPathCastStringToNumber:
3617 * @val: a string
3618 *
3619 * Converts a string to its number value
3620 *
3621 * Returns the number value
3622 */
3623double
3624xmlXPathCastStringToNumber(const xmlChar * val) {
3625 return(xmlXPathStringEvalNumber(val));
3626}
3627
3628/**
3629 * xmlXPathCastNodeToNumber:
3630 * @node: a node
3631 *
3632 * Converts a node to its number value
3633 *
3634 * Returns the number value
3635 */
3636double
3637xmlXPathCastNodeToNumber (xmlNodePtr node) {
3638 xmlChar *strval;
3639 double ret;
3640
3641 if (node == NULL)
3642 return(xmlXPathNAN);
3643 strval = xmlXPathCastNodeToString(node);
3644 if (strval == NULL)
3645 return(xmlXPathNAN);
3646 ret = xmlXPathCastStringToNumber(strval);
3647 xmlFree(strval);
3648
3649 return(ret);
3650}
3651
3652/**
3653 * xmlXPathCastNodeSetToNumber:
3654 * @ns: a node-set
3655 *
3656 * Converts a node-set to its number value
3657 *
3658 * Returns the number value
3659 */
3660double
3661xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3662 xmlChar *str;
3663 double ret;
3664
3665 if (ns == NULL)
3666 return(xmlXPathNAN);
3667 str = xmlXPathCastNodeSetToString(ns);
3668 ret = xmlXPathCastStringToNumber(str);
3669 xmlFree(str);
3670 return(ret);
3671}
3672
3673/**
3674 * xmlXPathCastToNumber:
3675 * @val: an XPath object
3676 *
3677 * Converts an XPath object to its number value
3678 *
3679 * Returns the number value
3680 */
3681double
3682xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3683 double ret = 0.0;
3684
3685 if (val == NULL)
3686 return(xmlXPathNAN);
3687 switch (val->type) {
3688 case XPATH_UNDEFINED:
3689#ifdef DEGUB_EXPR
3690 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3691#endif
3692 ret = xmlXPathNAN;
3693 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003694 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003695 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003696 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3697 break;
3698 case XPATH_STRING:
3699 ret = xmlXPathCastStringToNumber(val->stringval);
3700 break;
3701 case XPATH_NUMBER:
3702 ret = val->floatval;
3703 break;
3704 case XPATH_BOOLEAN:
3705 ret = xmlXPathCastBooleanToNumber(val->boolval);
3706 break;
3707 case XPATH_USERS:
3708 case XPATH_POINT:
3709 case XPATH_RANGE:
3710 case XPATH_LOCATIONSET:
3711 TODO;
3712 ret = xmlXPathNAN;
3713 break;
3714 }
3715 return(ret);
3716}
3717
3718/**
3719 * xmlXPathConvertNumber:
3720 * @val: an XPath object
3721 *
3722 * Converts an existing object to its number() equivalent
3723 *
3724 * Returns the new object, the old one is freed (or the operation
3725 * is done directly on @val)
3726 */
3727xmlXPathObjectPtr
3728xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3729 xmlXPathObjectPtr ret;
3730
3731 if (val == NULL)
3732 return(xmlXPathNewFloat(0.0));
3733 if (val->type == XPATH_NUMBER)
3734 return(val);
3735 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3736 xmlXPathFreeObject(val);
3737 return(ret);
3738}
3739
3740/**
3741 * xmlXPathCastNumberToBoolean:
3742 * @val: a number
3743 *
3744 * Converts a number to its boolean value
3745 *
3746 * Returns the boolean value
3747 */
3748int
3749xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003750 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003751 return(0);
3752 return(1);
3753}
3754
3755/**
3756 * xmlXPathCastStringToBoolean:
3757 * @val: a string
3758 *
3759 * Converts a string to its boolean value
3760 *
3761 * Returns the boolean value
3762 */
3763int
3764xmlXPathCastStringToBoolean (const xmlChar *val) {
3765 if ((val == NULL) || (xmlStrlen(val) == 0))
3766 return(0);
3767 return(1);
3768}
3769
3770/**
3771 * xmlXPathCastNodeSetToBoolean:
3772 * @ns: a node-set
3773 *
3774 * Converts a node-set to its boolean value
3775 *
3776 * Returns the boolean value
3777 */
3778int
3779xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3780 if ((ns == NULL) || (ns->nodeNr == 0))
3781 return(0);
3782 return(1);
3783}
3784
3785/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003786 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003787 * @val: an XPath object
3788 *
3789 * Converts an XPath object to its boolean value
3790 *
3791 * Returns the boolean value
3792 */
3793int
3794xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3795 int ret = 0;
3796
3797 if (val == NULL)
3798 return(0);
3799 switch (val->type) {
3800 case XPATH_UNDEFINED:
3801#ifdef DEBUG_EXPR
3802 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3803#endif
3804 ret = 0;
3805 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003806 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003807 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003808 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3809 break;
3810 case XPATH_STRING:
3811 ret = xmlXPathCastStringToBoolean(val->stringval);
3812 break;
3813 case XPATH_NUMBER:
3814 ret = xmlXPathCastNumberToBoolean(val->floatval);
3815 break;
3816 case XPATH_BOOLEAN:
3817 ret = val->boolval;
3818 break;
3819 case XPATH_USERS:
3820 case XPATH_POINT:
3821 case XPATH_RANGE:
3822 case XPATH_LOCATIONSET:
3823 TODO;
3824 ret = 0;
3825 break;
3826 }
3827 return(ret);
3828}
3829
3830
3831/**
3832 * xmlXPathConvertBoolean:
3833 * @val: an XPath object
3834 *
3835 * Converts an existing object to its boolean() equivalent
3836 *
3837 * Returns the new object, the old one is freed (or the operation
3838 * is done directly on @val)
3839 */
3840xmlXPathObjectPtr
3841xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3842 xmlXPathObjectPtr ret;
3843
3844 if (val == NULL)
3845 return(xmlXPathNewBoolean(0));
3846 if (val->type == XPATH_BOOLEAN)
3847 return(val);
3848 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3849 xmlXPathFreeObject(val);
3850 return(ret);
3851}
3852
Owen Taylor3473f882001-02-23 17:55:21 +00003853/************************************************************************
3854 * *
3855 * Routines to handle XPath contexts *
3856 * *
3857 ************************************************************************/
3858
3859/**
3860 * xmlXPathNewContext:
3861 * @doc: the XML document
3862 *
3863 * Create a new xmlXPathContext
3864 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003865 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003866 */
3867xmlXPathContextPtr
3868xmlXPathNewContext(xmlDocPtr doc) {
3869 xmlXPathContextPtr ret;
3870
3871 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3872 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003873 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003874 return(NULL);
3875 }
3876 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3877 ret->doc = doc;
3878 ret->node = NULL;
3879
3880 ret->varHash = NULL;
3881
3882 ret->nb_types = 0;
3883 ret->max_types = 0;
3884 ret->types = NULL;
3885
3886 ret->funcHash = xmlHashCreate(0);
3887
3888 ret->nb_axis = 0;
3889 ret->max_axis = 0;
3890 ret->axis = NULL;
3891
3892 ret->nsHash = NULL;
3893 ret->user = NULL;
3894
3895 ret->contextSize = -1;
3896 ret->proximityPosition = -1;
3897
3898 xmlXPathRegisterAllFunctions(ret);
3899
3900 return(ret);
3901}
3902
3903/**
3904 * xmlXPathFreeContext:
3905 * @ctxt: the context to free
3906 *
3907 * Free up an xmlXPathContext
3908 */
3909void
3910xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3911 xmlXPathRegisteredNsCleanup(ctxt);
3912 xmlXPathRegisteredFuncsCleanup(ctxt);
3913 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003914 xmlFree(ctxt);
3915}
3916
3917/************************************************************************
3918 * *
3919 * Routines to handle XPath parser contexts *
3920 * *
3921 ************************************************************************/
3922
3923#define CHECK_CTXT(ctxt) \
3924 if (ctxt == NULL) { \
3925 xmlGenericError(xmlGenericErrorContext, \
3926 "%s:%d Internal error: ctxt == NULL\n", \
3927 __FILE__, __LINE__); \
3928 } \
3929
3930
3931#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00003932 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
3933 (ctxt->doc->children == NULL)) { \
3934 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00003935 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00003936 }
Owen Taylor3473f882001-02-23 17:55:21 +00003937
3938
3939/**
3940 * xmlXPathNewParserContext:
3941 * @str: the XPath expression
3942 * @ctxt: the XPath context
3943 *
3944 * Create a new xmlXPathParserContext
3945 *
3946 * Returns the xmlXPathParserContext just allocated.
3947 */
3948xmlXPathParserContextPtr
3949xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3950 xmlXPathParserContextPtr ret;
3951
3952 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3953 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003954 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003955 return(NULL);
3956 }
3957 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3958 ret->cur = ret->base = str;
3959 ret->context = ctxt;
3960
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003961 ret->comp = xmlXPathNewCompExpr();
3962 if (ret->comp == NULL) {
3963 xmlFree(ret->valueTab);
3964 xmlFree(ret);
3965 return(NULL);
3966 }
Daniel Veillard4773df22004-01-23 13:15:13 +00003967 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
3968 ret->comp->dict = ctxt->dict;
3969 xmlDictReference(ret->comp->dict);
3970 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003971
3972 return(ret);
3973}
3974
3975/**
3976 * xmlXPathCompParserContext:
3977 * @comp: the XPath compiled expression
3978 * @ctxt: the XPath context
3979 *
3980 * Create a new xmlXPathParserContext when processing a compiled expression
3981 *
3982 * Returns the xmlXPathParserContext just allocated.
3983 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003984static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003985xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3986 xmlXPathParserContextPtr ret;
3987
3988 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3989 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003990 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003991 return(NULL);
3992 }
3993 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3994
Owen Taylor3473f882001-02-23 17:55:21 +00003995 /* Allocate the value stack */
3996 ret->valueTab = (xmlXPathObjectPtr *)
3997 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003998 if (ret->valueTab == NULL) {
3999 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004000 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004001 return(NULL);
4002 }
Owen Taylor3473f882001-02-23 17:55:21 +00004003 ret->valueNr = 0;
4004 ret->valueMax = 10;
4005 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004006
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004007 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004008 ret->comp = comp;
4009
Owen Taylor3473f882001-02-23 17:55:21 +00004010 return(ret);
4011}
4012
4013/**
4014 * xmlXPathFreeParserContext:
4015 * @ctxt: the context to free
4016 *
4017 * Free up an xmlXPathParserContext
4018 */
4019void
4020xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
4021 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004022 xmlFree(ctxt->valueTab);
4023 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004024 if (ctxt->comp)
4025 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00004026 xmlFree(ctxt);
4027}
4028
4029/************************************************************************
4030 * *
4031 * The implicit core function library *
4032 * *
4033 ************************************************************************/
4034
Owen Taylor3473f882001-02-23 17:55:21 +00004035/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004036 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00004037 * @node: a node pointer
4038 *
4039 * Function computing the beginning of the string value of the node,
4040 * used to speed up comparisons
4041 *
4042 * Returns an int usable as a hash
4043 */
4044static unsigned int
4045xmlXPathNodeValHash(xmlNodePtr node) {
4046 int len = 2;
4047 const xmlChar * string = NULL;
4048 xmlNodePtr tmp = NULL;
4049 unsigned int ret = 0;
4050
4051 if (node == NULL)
4052 return(0);
4053
Daniel Veillard9adc0462003-03-24 18:39:54 +00004054 if (node->type == XML_DOCUMENT_NODE) {
4055 tmp = xmlDocGetRootElement((xmlDocPtr) node);
4056 if (tmp == NULL)
4057 node = node->children;
4058 else
4059 node = tmp;
4060
4061 if (node == NULL)
4062 return(0);
4063 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004064
4065 switch (node->type) {
4066 case XML_COMMENT_NODE:
4067 case XML_PI_NODE:
4068 case XML_CDATA_SECTION_NODE:
4069 case XML_TEXT_NODE:
4070 string = node->content;
4071 if (string == NULL)
4072 return(0);
4073 if (string[0] == 0)
4074 return(0);
4075 return(((unsigned int) string[0]) +
4076 (((unsigned int) string[1]) << 8));
4077 case XML_NAMESPACE_DECL:
4078 string = ((xmlNsPtr)node)->href;
4079 if (string == NULL)
4080 return(0);
4081 if (string[0] == 0)
4082 return(0);
4083 return(((unsigned int) string[0]) +
4084 (((unsigned int) string[1]) << 8));
4085 case XML_ATTRIBUTE_NODE:
4086 tmp = ((xmlAttrPtr) node)->children;
4087 break;
4088 case XML_ELEMENT_NODE:
4089 tmp = node->children;
4090 break;
4091 default:
4092 return(0);
4093 }
4094 while (tmp != NULL) {
4095 switch (tmp->type) {
4096 case XML_COMMENT_NODE:
4097 case XML_PI_NODE:
4098 case XML_CDATA_SECTION_NODE:
4099 case XML_TEXT_NODE:
4100 string = tmp->content;
4101 break;
4102 case XML_NAMESPACE_DECL:
4103 string = ((xmlNsPtr)tmp)->href;
4104 break;
4105 default:
4106 break;
4107 }
4108 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004109 if (len == 1) {
4110 return(ret + (((unsigned int) string[0]) << 8));
4111 }
4112 if (string[1] == 0) {
4113 len = 1;
4114 ret = (unsigned int) string[0];
4115 } else {
4116 return(((unsigned int) string[0]) +
4117 (((unsigned int) string[1]) << 8));
4118 }
4119 }
4120 /*
4121 * Skip to next node
4122 */
4123 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4124 if (tmp->children->type != XML_ENTITY_DECL) {
4125 tmp = tmp->children;
4126 continue;
4127 }
4128 }
4129 if (tmp == node)
4130 break;
4131
4132 if (tmp->next != NULL) {
4133 tmp = tmp->next;
4134 continue;
4135 }
4136
4137 do {
4138 tmp = tmp->parent;
4139 if (tmp == NULL)
4140 break;
4141 if (tmp == node) {
4142 tmp = NULL;
4143 break;
4144 }
4145 if (tmp->next != NULL) {
4146 tmp = tmp->next;
4147 break;
4148 }
4149 } while (tmp != NULL);
4150 }
4151 return(ret);
4152}
4153
4154/**
4155 * xmlXPathStringHash:
4156 * @string: a string
4157 *
4158 * Function computing the beginning of the string value of the node,
4159 * used to speed up comparisons
4160 *
4161 * Returns an int usable as a hash
4162 */
4163static unsigned int
4164xmlXPathStringHash(const xmlChar * string) {
4165 if (string == NULL)
4166 return((unsigned int) 0);
4167 if (string[0] == 0)
4168 return(0);
4169 return(((unsigned int) string[0]) +
4170 (((unsigned int) string[1]) << 8));
4171}
4172
4173/**
Owen Taylor3473f882001-02-23 17:55:21 +00004174 * xmlXPathCompareNodeSetFloat:
4175 * @ctxt: the XPath Parser context
4176 * @inf: less than (1) or greater than (0)
4177 * @strict: is the comparison strict
4178 * @arg: the node set
4179 * @f: the value
4180 *
4181 * Implement the compare operation between a nodeset and a number
4182 * @ns < @val (1, 1, ...
4183 * @ns <= @val (1, 0, ...
4184 * @ns > @val (0, 1, ...
4185 * @ns >= @val (0, 0, ...
4186 *
4187 * If one object to be compared is a node-set and the other is a number,
4188 * then the comparison will be true if and only if there is a node in the
4189 * node-set such that the result of performing the comparison on the number
4190 * to be compared and on the result of converting the string-value of that
4191 * node to a number using the number function is true.
4192 *
4193 * Returns 0 or 1 depending on the results of the test.
4194 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004195static int
Owen Taylor3473f882001-02-23 17:55:21 +00004196xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4197 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4198 int i, ret = 0;
4199 xmlNodeSetPtr ns;
4200 xmlChar *str2;
4201
4202 if ((f == NULL) || (arg == NULL) ||
4203 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4204 xmlXPathFreeObject(arg);
4205 xmlXPathFreeObject(f);
4206 return(0);
4207 }
4208 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004209 if (ns != NULL) {
4210 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004211 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004212 if (str2 != NULL) {
4213 valuePush(ctxt,
4214 xmlXPathNewString(str2));
4215 xmlFree(str2);
4216 xmlXPathNumberFunction(ctxt, 1);
4217 valuePush(ctxt, xmlXPathObjectCopy(f));
4218 ret = xmlXPathCompareValues(ctxt, inf, strict);
4219 if (ret)
4220 break;
4221 }
4222 }
Owen Taylor3473f882001-02-23 17:55:21 +00004223 }
4224 xmlXPathFreeObject(arg);
4225 xmlXPathFreeObject(f);
4226 return(ret);
4227}
4228
4229/**
4230 * xmlXPathCompareNodeSetString:
4231 * @ctxt: the XPath Parser context
4232 * @inf: less than (1) or greater than (0)
4233 * @strict: is the comparison strict
4234 * @arg: the node set
4235 * @s: the value
4236 *
4237 * Implement the compare operation between a nodeset and a string
4238 * @ns < @val (1, 1, ...
4239 * @ns <= @val (1, 0, ...
4240 * @ns > @val (0, 1, ...
4241 * @ns >= @val (0, 0, ...
4242 *
4243 * If one object to be compared is a node-set and the other is a string,
4244 * then the comparison will be true if and only if there is a node in
4245 * the node-set such that the result of performing the comparison on the
4246 * string-value of the node and the other string is true.
4247 *
4248 * Returns 0 or 1 depending on the results of the test.
4249 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004250static int
Owen Taylor3473f882001-02-23 17:55:21 +00004251xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4252 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4253 int i, ret = 0;
4254 xmlNodeSetPtr ns;
4255 xmlChar *str2;
4256
4257 if ((s == NULL) || (arg == NULL) ||
4258 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4259 xmlXPathFreeObject(arg);
4260 xmlXPathFreeObject(s);
4261 return(0);
4262 }
4263 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004264 if (ns != NULL) {
4265 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004266 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004267 if (str2 != NULL) {
4268 valuePush(ctxt,
4269 xmlXPathNewString(str2));
4270 xmlFree(str2);
4271 valuePush(ctxt, xmlXPathObjectCopy(s));
4272 ret = xmlXPathCompareValues(ctxt, inf, strict);
4273 if (ret)
4274 break;
4275 }
4276 }
Owen Taylor3473f882001-02-23 17:55:21 +00004277 }
4278 xmlXPathFreeObject(arg);
4279 xmlXPathFreeObject(s);
4280 return(ret);
4281}
4282
4283/**
4284 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004285 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004286 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004287 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004288 * @arg2: the second node set object
4289 *
4290 * Implement the compare operation on nodesets:
4291 *
4292 * If both objects to be compared are node-sets, then the comparison
4293 * will be true if and only if there is a node in the first node-set
4294 * and a node in the second node-set such that the result of performing
4295 * the comparison on the string-values of the two nodes is true.
4296 * ....
4297 * When neither object to be compared is a node-set and the operator
4298 * is <=, <, >= or >, then the objects are compared by converting both
4299 * objects to numbers and comparing the numbers according to IEEE 754.
4300 * ....
4301 * The number function converts its argument to a number as follows:
4302 * - a string that consists of optional whitespace followed by an
4303 * optional minus sign followed by a Number followed by whitespace
4304 * is converted to the IEEE 754 number that is nearest (according
4305 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4306 * represented by the string; any other string is converted to NaN
4307 *
4308 * Conclusion all nodes need to be converted first to their string value
4309 * and then the comparison must be done when possible
4310 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004311static int
4312xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004313 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4314 int i, j, init = 0;
4315 double val1;
4316 double *values2;
4317 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004318 xmlNodeSetPtr ns1;
4319 xmlNodeSetPtr ns2;
4320
4321 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004322 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4323 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004324 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004325 }
Owen Taylor3473f882001-02-23 17:55:21 +00004326 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004327 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4328 xmlXPathFreeObject(arg1);
4329 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004330 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004331 }
Owen Taylor3473f882001-02-23 17:55:21 +00004332
4333 ns1 = arg1->nodesetval;
4334 ns2 = arg2->nodesetval;
4335
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004336 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004337 xmlXPathFreeObject(arg1);
4338 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004339 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004340 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004341 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004342 xmlXPathFreeObject(arg1);
4343 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004344 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004345 }
Owen Taylor3473f882001-02-23 17:55:21 +00004346
4347 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4348 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004349 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004350 xmlXPathFreeObject(arg1);
4351 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004352 return(0);
4353 }
4354 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004355 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004356 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004357 continue;
4358 for (j = 0;j < ns2->nodeNr;j++) {
4359 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004360 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004361 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004362 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004363 continue;
4364 if (inf && strict)
4365 ret = (val1 < values2[j]);
4366 else if (inf && !strict)
4367 ret = (val1 <= values2[j]);
4368 else if (!inf && strict)
4369 ret = (val1 > values2[j]);
4370 else if (!inf && !strict)
4371 ret = (val1 >= values2[j]);
4372 if (ret)
4373 break;
4374 }
4375 if (ret)
4376 break;
4377 init = 1;
4378 }
4379 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004380 xmlXPathFreeObject(arg1);
4381 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004382 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004383}
4384
4385/**
4386 * xmlXPathCompareNodeSetValue:
4387 * @ctxt: the XPath Parser context
4388 * @inf: less than (1) or greater than (0)
4389 * @strict: is the comparison strict
4390 * @arg: the node set
4391 * @val: the value
4392 *
4393 * Implement the compare operation between a nodeset and a value
4394 * @ns < @val (1, 1, ...
4395 * @ns <= @val (1, 0, ...
4396 * @ns > @val (0, 1, ...
4397 * @ns >= @val (0, 0, ...
4398 *
4399 * If one object to be compared is a node-set and the other is a boolean,
4400 * then the comparison will be true if and only if the result of performing
4401 * the comparison on the boolean and on the result of converting
4402 * the node-set to a boolean using the boolean function is true.
4403 *
4404 * Returns 0 or 1 depending on the results of the test.
4405 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004406static int
Owen Taylor3473f882001-02-23 17:55:21 +00004407xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4408 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4409 if ((val == NULL) || (arg == NULL) ||
4410 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4411 return(0);
4412
4413 switch(val->type) {
4414 case XPATH_NUMBER:
4415 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4416 case XPATH_NODESET:
4417 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004418 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004419 case XPATH_STRING:
4420 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4421 case XPATH_BOOLEAN:
4422 valuePush(ctxt, arg);
4423 xmlXPathBooleanFunction(ctxt, 1);
4424 valuePush(ctxt, val);
4425 return(xmlXPathCompareValues(ctxt, inf, strict));
4426 default:
4427 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004428 }
4429 return(0);
4430}
4431
4432/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004433 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004434 * @arg: the nodeset object argument
4435 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004436 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004437 *
4438 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4439 * If one object to be compared is a node-set and the other is a string,
4440 * then the comparison will be true if and only if there is a node in
4441 * the node-set such that the result of performing the comparison on the
4442 * string-value of the node and the other string is true.
4443 *
4444 * Returns 0 or 1 depending on the results of the test.
4445 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004446static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004447xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004448{
Owen Taylor3473f882001-02-23 17:55:21 +00004449 int i;
4450 xmlNodeSetPtr ns;
4451 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004452 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004453
4454 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004455 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4456 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004457 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004458 /*
4459 * A NULL nodeset compared with a string is always false
4460 * (since there is no node equal, and no node not equal)
4461 */
4462 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004463 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004464 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004465 for (i = 0; i < ns->nodeNr; i++) {
4466 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4467 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4468 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4469 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004470 if (neq)
4471 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004472 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004473 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4474 if (neq)
4475 continue;
4476 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004477 } else if (neq) {
4478 if (str2 != NULL)
4479 xmlFree(str2);
4480 return (1);
4481 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004482 if (str2 != NULL)
4483 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004484 } else if (neq)
4485 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004486 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004487 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004488}
4489
4490/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004491 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004492 * @arg: the nodeset object argument
4493 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004494 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004495 *
4496 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4497 * If one object to be compared is a node-set and the other is a number,
4498 * then the comparison will be true if and only if there is a node in
4499 * the node-set such that the result of performing the comparison on the
4500 * number to be compared and on the result of converting the string-value
4501 * of that node to a number using the number function is true.
4502 *
4503 * Returns 0 or 1 depending on the results of the test.
4504 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004505static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004506xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4507 xmlXPathObjectPtr arg, double f, int neq) {
4508 int i, ret=0;
4509 xmlNodeSetPtr ns;
4510 xmlChar *str2;
4511 xmlXPathObjectPtr val;
4512 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004513
4514 if ((arg == NULL) ||
4515 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4516 return(0);
4517
William M. Brack0c022ad2002-07-12 00:56:01 +00004518 ns = arg->nodesetval;
4519 if (ns != NULL) {
4520 for (i=0;i<ns->nodeNr;i++) {
4521 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4522 if (str2 != NULL) {
4523 valuePush(ctxt, xmlXPathNewString(str2));
4524 xmlFree(str2);
4525 xmlXPathNumberFunction(ctxt, 1);
4526 val = valuePop(ctxt);
4527 v = val->floatval;
4528 xmlXPathFreeObject(val);
4529 if (!xmlXPathIsNaN(v)) {
4530 if ((!neq) && (v==f)) {
4531 ret = 1;
4532 break;
4533 } else if ((neq) && (v!=f)) {
4534 ret = 1;
4535 break;
4536 }
4537 }
4538 }
4539 }
4540 }
4541
4542 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004543}
4544
4545
4546/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004547 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004548 * @arg1: first nodeset object argument
4549 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004550 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004551 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004552 * Implement the equal / not equal operation on XPath nodesets:
4553 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004554 * If both objects to be compared are node-sets, then the comparison
4555 * will be true if and only if there is a node in the first node-set and
4556 * a node in the second node-set such that the result of performing the
4557 * comparison on the string-values of the two nodes is true.
4558 *
4559 * (needless to say, this is a costly operation)
4560 *
4561 * Returns 0 or 1 depending on the results of the test.
4562 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004563static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004564xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004565 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004566 unsigned int *hashs1;
4567 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004568 xmlChar **values1;
4569 xmlChar **values2;
4570 int ret = 0;
4571 xmlNodeSetPtr ns1;
4572 xmlNodeSetPtr ns2;
4573
4574 if ((arg1 == NULL) ||
4575 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4576 return(0);
4577 if ((arg2 == NULL) ||
4578 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4579 return(0);
4580
4581 ns1 = arg1->nodesetval;
4582 ns2 = arg2->nodesetval;
4583
Daniel Veillard911f49a2001-04-07 15:39:35 +00004584 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004585 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004586 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004587 return(0);
4588
4589 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004590 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004591 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004592 if (neq == 0)
4593 for (i = 0;i < ns1->nodeNr;i++)
4594 for (j = 0;j < ns2->nodeNr;j++)
4595 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4596 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004597
4598 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004599 if (values1 == NULL) {
4600 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004601 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004602 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004603 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4604 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004605 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004606 xmlFree(values1);
4607 return(0);
4608 }
Owen Taylor3473f882001-02-23 17:55:21 +00004609 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4610 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4611 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004612 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004613 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004614 xmlFree(values1);
4615 return(0);
4616 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004617 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4618 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004619 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004620 xmlFree(hashs1);
4621 xmlFree(values1);
4622 xmlFree(values2);
4623 return(0);
4624 }
Owen Taylor3473f882001-02-23 17:55:21 +00004625 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4626 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004627 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004628 for (j = 0;j < ns2->nodeNr;j++) {
4629 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004630 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004631 if (hashs1[i] != hashs2[j]) {
4632 if (neq) {
4633 ret = 1;
4634 break;
4635 }
4636 }
4637 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004638 if (values1[i] == NULL)
4639 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4640 if (values2[j] == NULL)
4641 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004642 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004643 if (ret)
4644 break;
4645 }
Owen Taylor3473f882001-02-23 17:55:21 +00004646 }
4647 if (ret)
4648 break;
4649 }
4650 for (i = 0;i < ns1->nodeNr;i++)
4651 if (values1[i] != NULL)
4652 xmlFree(values1[i]);
4653 for (j = 0;j < ns2->nodeNr;j++)
4654 if (values2[j] != NULL)
4655 xmlFree(values2[j]);
4656 xmlFree(values1);
4657 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004658 xmlFree(hashs1);
4659 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004660 return(ret);
4661}
4662
William M. Brack0c022ad2002-07-12 00:56:01 +00004663static int
4664xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4665 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004666 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004667 /*
4668 *At this point we are assured neither arg1 nor arg2
4669 *is a nodeset, so we can just pick the appropriate routine.
4670 */
Owen Taylor3473f882001-02-23 17:55:21 +00004671 switch (arg1->type) {
4672 case XPATH_UNDEFINED:
4673#ifdef DEBUG_EXPR
4674 xmlGenericError(xmlGenericErrorContext,
4675 "Equal: undefined\n");
4676#endif
4677 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004678 case XPATH_BOOLEAN:
4679 switch (arg2->type) {
4680 case XPATH_UNDEFINED:
4681#ifdef DEBUG_EXPR
4682 xmlGenericError(xmlGenericErrorContext,
4683 "Equal: undefined\n");
4684#endif
4685 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004686 case XPATH_BOOLEAN:
4687#ifdef DEBUG_EXPR
4688 xmlGenericError(xmlGenericErrorContext,
4689 "Equal: %d boolean %d \n",
4690 arg1->boolval, arg2->boolval);
4691#endif
4692 ret = (arg1->boolval == arg2->boolval);
4693 break;
4694 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004695 ret = (arg1->boolval ==
4696 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004697 break;
4698 case XPATH_STRING:
4699 if ((arg2->stringval == NULL) ||
4700 (arg2->stringval[0] == 0)) ret = 0;
4701 else
4702 ret = 1;
4703 ret = (arg1->boolval == ret);
4704 break;
4705 case XPATH_USERS:
4706 case XPATH_POINT:
4707 case XPATH_RANGE:
4708 case XPATH_LOCATIONSET:
4709 TODO
4710 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004711 case XPATH_NODESET:
4712 case XPATH_XSLT_TREE:
4713 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004714 }
4715 break;
4716 case XPATH_NUMBER:
4717 switch (arg2->type) {
4718 case XPATH_UNDEFINED:
4719#ifdef DEBUG_EXPR
4720 xmlGenericError(xmlGenericErrorContext,
4721 "Equal: undefined\n");
4722#endif
4723 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004724 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004725 ret = (arg2->boolval==
4726 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004727 break;
4728 case XPATH_STRING:
4729 valuePush(ctxt, arg2);
4730 xmlXPathNumberFunction(ctxt, 1);
4731 arg2 = valuePop(ctxt);
4732 /* no break on purpose */
4733 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004734 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004735 if (xmlXPathIsNaN(arg1->floatval) ||
4736 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004737 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004738 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4739 if (xmlXPathIsInf(arg2->floatval) == 1)
4740 ret = 1;
4741 else
4742 ret = 0;
4743 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4744 if (xmlXPathIsInf(arg2->floatval) == -1)
4745 ret = 1;
4746 else
4747 ret = 0;
4748 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4749 if (xmlXPathIsInf(arg1->floatval) == 1)
4750 ret = 1;
4751 else
4752 ret = 0;
4753 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4754 if (xmlXPathIsInf(arg1->floatval) == -1)
4755 ret = 1;
4756 else
4757 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004758 } else {
4759 ret = (arg1->floatval == arg2->floatval);
4760 }
Owen Taylor3473f882001-02-23 17:55:21 +00004761 break;
4762 case XPATH_USERS:
4763 case XPATH_POINT:
4764 case XPATH_RANGE:
4765 case XPATH_LOCATIONSET:
4766 TODO
4767 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004768 case XPATH_NODESET:
4769 case XPATH_XSLT_TREE:
4770 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004771 }
4772 break;
4773 case XPATH_STRING:
4774 switch (arg2->type) {
4775 case XPATH_UNDEFINED:
4776#ifdef DEBUG_EXPR
4777 xmlGenericError(xmlGenericErrorContext,
4778 "Equal: undefined\n");
4779#endif
4780 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004781 case XPATH_BOOLEAN:
4782 if ((arg1->stringval == NULL) ||
4783 (arg1->stringval[0] == 0)) ret = 0;
4784 else
4785 ret = 1;
4786 ret = (arg2->boolval == ret);
4787 break;
4788 case XPATH_STRING:
4789 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4790 break;
4791 case XPATH_NUMBER:
4792 valuePush(ctxt, arg1);
4793 xmlXPathNumberFunction(ctxt, 1);
4794 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004795 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004796 if (xmlXPathIsNaN(arg1->floatval) ||
4797 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004798 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004799 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4800 if (xmlXPathIsInf(arg2->floatval) == 1)
4801 ret = 1;
4802 else
4803 ret = 0;
4804 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4805 if (xmlXPathIsInf(arg2->floatval) == -1)
4806 ret = 1;
4807 else
4808 ret = 0;
4809 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4810 if (xmlXPathIsInf(arg1->floatval) == 1)
4811 ret = 1;
4812 else
4813 ret = 0;
4814 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4815 if (xmlXPathIsInf(arg1->floatval) == -1)
4816 ret = 1;
4817 else
4818 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004819 } else {
4820 ret = (arg1->floatval == arg2->floatval);
4821 }
Owen Taylor3473f882001-02-23 17:55:21 +00004822 break;
4823 case XPATH_USERS:
4824 case XPATH_POINT:
4825 case XPATH_RANGE:
4826 case XPATH_LOCATIONSET:
4827 TODO
4828 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004829 case XPATH_NODESET:
4830 case XPATH_XSLT_TREE:
4831 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004832 }
4833 break;
4834 case XPATH_USERS:
4835 case XPATH_POINT:
4836 case XPATH_RANGE:
4837 case XPATH_LOCATIONSET:
4838 TODO
4839 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004840 case XPATH_NODESET:
4841 case XPATH_XSLT_TREE:
4842 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004843 }
4844 xmlXPathFreeObject(arg1);
4845 xmlXPathFreeObject(arg2);
4846 return(ret);
4847}
4848
William M. Brack0c022ad2002-07-12 00:56:01 +00004849/**
4850 * xmlXPathEqualValues:
4851 * @ctxt: the XPath Parser context
4852 *
4853 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4854 *
4855 * Returns 0 or 1 depending on the results of the test.
4856 */
4857int
4858xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4859 xmlXPathObjectPtr arg1, arg2, argtmp;
4860 int ret = 0;
4861
4862 arg2 = valuePop(ctxt);
4863 arg1 = valuePop(ctxt);
4864 if ((arg1 == NULL) || (arg2 == NULL)) {
4865 if (arg1 != NULL)
4866 xmlXPathFreeObject(arg1);
4867 else
4868 xmlXPathFreeObject(arg2);
4869 XP_ERROR0(XPATH_INVALID_OPERAND);
4870 }
4871
4872 if (arg1 == arg2) {
4873#ifdef DEBUG_EXPR
4874 xmlGenericError(xmlGenericErrorContext,
4875 "Equal: by pointer\n");
4876#endif
4877 return(1);
4878 }
4879
4880 /*
4881 *If either argument is a nodeset, it's a 'special case'
4882 */
4883 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4884 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4885 /*
4886 *Hack it to assure arg1 is the nodeset
4887 */
4888 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4889 argtmp = arg2;
4890 arg2 = arg1;
4891 arg1 = argtmp;
4892 }
4893 switch (arg2->type) {
4894 case XPATH_UNDEFINED:
4895#ifdef DEBUG_EXPR
4896 xmlGenericError(xmlGenericErrorContext,
4897 "Equal: undefined\n");
4898#endif
4899 break;
4900 case XPATH_NODESET:
4901 case XPATH_XSLT_TREE:
4902 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4903 break;
4904 case XPATH_BOOLEAN:
4905 if ((arg1->nodesetval == NULL) ||
4906 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4907 else
4908 ret = 1;
4909 ret = (ret == arg2->boolval);
4910 break;
4911 case XPATH_NUMBER:
4912 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4913 break;
4914 case XPATH_STRING:
4915 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4916 break;
4917 case XPATH_USERS:
4918 case XPATH_POINT:
4919 case XPATH_RANGE:
4920 case XPATH_LOCATIONSET:
4921 TODO
4922 break;
4923 }
4924 xmlXPathFreeObject(arg1);
4925 xmlXPathFreeObject(arg2);
4926 return(ret);
4927 }
4928
4929 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4930}
4931
4932/**
4933 * xmlXPathNotEqualValues:
4934 * @ctxt: the XPath Parser context
4935 *
4936 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4937 *
4938 * Returns 0 or 1 depending on the results of the test.
4939 */
4940int
4941xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4942 xmlXPathObjectPtr arg1, arg2, argtmp;
4943 int ret = 0;
4944
4945 arg2 = valuePop(ctxt);
4946 arg1 = valuePop(ctxt);
4947 if ((arg1 == NULL) || (arg2 == NULL)) {
4948 if (arg1 != NULL)
4949 xmlXPathFreeObject(arg1);
4950 else
4951 xmlXPathFreeObject(arg2);
4952 XP_ERROR0(XPATH_INVALID_OPERAND);
4953 }
4954
4955 if (arg1 == arg2) {
4956#ifdef DEBUG_EXPR
4957 xmlGenericError(xmlGenericErrorContext,
4958 "NotEqual: by pointer\n");
4959#endif
4960 return(0);
4961 }
4962
4963 /*
4964 *If either argument is a nodeset, it's a 'special case'
4965 */
4966 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4967 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4968 /*
4969 *Hack it to assure arg1 is the nodeset
4970 */
4971 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4972 argtmp = arg2;
4973 arg2 = arg1;
4974 arg1 = argtmp;
4975 }
4976 switch (arg2->type) {
4977 case XPATH_UNDEFINED:
4978#ifdef DEBUG_EXPR
4979 xmlGenericError(xmlGenericErrorContext,
4980 "NotEqual: undefined\n");
4981#endif
4982 break;
4983 case XPATH_NODESET:
4984 case XPATH_XSLT_TREE:
4985 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4986 break;
4987 case XPATH_BOOLEAN:
4988 if ((arg1->nodesetval == NULL) ||
4989 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4990 else
4991 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004992 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004993 break;
4994 case XPATH_NUMBER:
4995 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4996 break;
4997 case XPATH_STRING:
4998 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4999 break;
5000 case XPATH_USERS:
5001 case XPATH_POINT:
5002 case XPATH_RANGE:
5003 case XPATH_LOCATIONSET:
5004 TODO
5005 break;
5006 }
5007 xmlXPathFreeObject(arg1);
5008 xmlXPathFreeObject(arg2);
5009 return(ret);
5010 }
5011
5012 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5013}
Owen Taylor3473f882001-02-23 17:55:21 +00005014
5015/**
5016 * xmlXPathCompareValues:
5017 * @ctxt: the XPath Parser context
5018 * @inf: less than (1) or greater than (0)
5019 * @strict: is the comparison strict
5020 *
5021 * Implement the compare operation on XPath objects:
5022 * @arg1 < @arg2 (1, 1, ...
5023 * @arg1 <= @arg2 (1, 0, ...
5024 * @arg1 > @arg2 (0, 1, ...
5025 * @arg1 >= @arg2 (0, 0, ...
5026 *
5027 * When neither object to be compared is a node-set and the operator is
5028 * <=, <, >=, >, then the objects are compared by converted both objects
5029 * to numbers and comparing the numbers according to IEEE 754. The <
5030 * comparison will be true if and only if the first number is less than the
5031 * second number. The <= comparison will be true if and only if the first
5032 * number is less than or equal to the second number. The > comparison
5033 * will be true if and only if the first number is greater than the second
5034 * number. The >= comparison will be true if and only if the first number
5035 * is greater than or equal to the second number.
5036 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005037 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005038 */
5039int
5040xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005041 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005042 xmlXPathObjectPtr arg1, arg2;
5043
William M. Brack0c022ad2002-07-12 00:56:01 +00005044 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005045 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005046 if ((arg1 == NULL) || (arg2 == NULL)) {
5047 if (arg1 != NULL)
5048 xmlXPathFreeObject(arg1);
5049 else
5050 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005051 XP_ERROR0(XPATH_INVALID_OPERAND);
5052 }
5053
William M. Brack0c022ad2002-07-12 00:56:01 +00005054 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5055 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5056 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5057 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005058 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005059 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005060 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005061 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5062 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005063 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005064 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5065 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005066 }
5067 }
5068 return(ret);
5069 }
5070
5071 if (arg1->type != XPATH_NUMBER) {
5072 valuePush(ctxt, arg1);
5073 xmlXPathNumberFunction(ctxt, 1);
5074 arg1 = valuePop(ctxt);
5075 }
5076 if (arg1->type != XPATH_NUMBER) {
5077 xmlXPathFreeObject(arg1);
5078 xmlXPathFreeObject(arg2);
5079 XP_ERROR0(XPATH_INVALID_OPERAND);
5080 }
5081 if (arg2->type != XPATH_NUMBER) {
5082 valuePush(ctxt, arg2);
5083 xmlXPathNumberFunction(ctxt, 1);
5084 arg2 = valuePop(ctxt);
5085 }
5086 if (arg2->type != XPATH_NUMBER) {
5087 xmlXPathFreeObject(arg1);
5088 xmlXPathFreeObject(arg2);
5089 XP_ERROR0(XPATH_INVALID_OPERAND);
5090 }
5091 /*
5092 * Add tests for infinity and nan
5093 * => feedback on 3.4 for Inf and NaN
5094 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005095 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005096 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005097 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005098 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005099 arg1i=xmlXPathIsInf(arg1->floatval);
5100 arg2i=xmlXPathIsInf(arg2->floatval);
5101 if (inf && strict) {
5102 if ((arg1i == -1 && arg2i != -1) ||
5103 (arg2i == 1 && arg1i != 1)) {
5104 ret = 1;
5105 } else if (arg1i == 0 && arg2i == 0) {
5106 ret = (arg1->floatval < arg2->floatval);
5107 } else {
5108 ret = 0;
5109 }
5110 }
5111 else if (inf && !strict) {
5112 if (arg1i == -1 || arg2i == 1) {
5113 ret = 1;
5114 } else if (arg1i == 0 && arg2i == 0) {
5115 ret = (arg1->floatval <= arg2->floatval);
5116 } else {
5117 ret = 0;
5118 }
5119 }
5120 else if (!inf && strict) {
5121 if ((arg1i == 1 && arg2i != 1) ||
5122 (arg2i == -1 && arg1i != -1)) {
5123 ret = 1;
5124 } else if (arg1i == 0 && arg2i == 0) {
5125 ret = (arg1->floatval > arg2->floatval);
5126 } else {
5127 ret = 0;
5128 }
5129 }
5130 else if (!inf && !strict) {
5131 if (arg1i == 1 || arg2i == -1) {
5132 ret = 1;
5133 } else if (arg1i == 0 && arg2i == 0) {
5134 ret = (arg1->floatval >= arg2->floatval);
5135 } else {
5136 ret = 0;
5137 }
5138 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005139 }
Owen Taylor3473f882001-02-23 17:55:21 +00005140 xmlXPathFreeObject(arg1);
5141 xmlXPathFreeObject(arg2);
5142 return(ret);
5143}
5144
5145/**
5146 * xmlXPathValueFlipSign:
5147 * @ctxt: the XPath Parser context
5148 *
5149 * Implement the unary - operation on an XPath object
5150 * The numeric operators convert their operands to numbers as if
5151 * by calling the number function.
5152 */
5153void
5154xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005155 CAST_TO_NUMBER;
5156 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005157 if (xmlXPathIsNaN(ctxt->value->floatval))
5158 ctxt->value->floatval=xmlXPathNAN;
5159 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5160 ctxt->value->floatval=xmlXPathNINF;
5161 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5162 ctxt->value->floatval=xmlXPathPINF;
5163 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005164 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5165 ctxt->value->floatval = xmlXPathNZERO;
5166 else
5167 ctxt->value->floatval = 0;
5168 }
5169 else
5170 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005171}
5172
5173/**
5174 * xmlXPathAddValues:
5175 * @ctxt: the XPath Parser context
5176 *
5177 * Implement the add operation on XPath objects:
5178 * The numeric operators convert their operands to numbers as if
5179 * by calling the number function.
5180 */
5181void
5182xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5183 xmlXPathObjectPtr arg;
5184 double val;
5185
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005186 arg = valuePop(ctxt);
5187 if (arg == NULL)
5188 XP_ERROR(XPATH_INVALID_OPERAND);
5189 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005190 xmlXPathFreeObject(arg);
5191
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005192 CAST_TO_NUMBER;
5193 CHECK_TYPE(XPATH_NUMBER);
5194 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005195}
5196
5197/**
5198 * xmlXPathSubValues:
5199 * @ctxt: the XPath Parser context
5200 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005201 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005202 * The numeric operators convert their operands to numbers as if
5203 * by calling the number function.
5204 */
5205void
5206xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5207 xmlXPathObjectPtr arg;
5208 double val;
5209
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005210 arg = valuePop(ctxt);
5211 if (arg == NULL)
5212 XP_ERROR(XPATH_INVALID_OPERAND);
5213 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005214 xmlXPathFreeObject(arg);
5215
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005216 CAST_TO_NUMBER;
5217 CHECK_TYPE(XPATH_NUMBER);
5218 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005219}
5220
5221/**
5222 * xmlXPathMultValues:
5223 * @ctxt: the XPath Parser context
5224 *
5225 * Implement the multiply operation on XPath objects:
5226 * The numeric operators convert their operands to numbers as if
5227 * by calling the number function.
5228 */
5229void
5230xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5231 xmlXPathObjectPtr arg;
5232 double val;
5233
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005234 arg = valuePop(ctxt);
5235 if (arg == NULL)
5236 XP_ERROR(XPATH_INVALID_OPERAND);
5237 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005238 xmlXPathFreeObject(arg);
5239
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005240 CAST_TO_NUMBER;
5241 CHECK_TYPE(XPATH_NUMBER);
5242 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005243}
5244
5245/**
5246 * xmlXPathDivValues:
5247 * @ctxt: the XPath Parser context
5248 *
5249 * Implement the div operation on XPath objects @arg1 / @arg2:
5250 * The numeric operators convert their operands to numbers as if
5251 * by calling the number function.
5252 */
5253void
5254xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5255 xmlXPathObjectPtr arg;
5256 double val;
5257
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005258 arg = valuePop(ctxt);
5259 if (arg == NULL)
5260 XP_ERROR(XPATH_INVALID_OPERAND);
5261 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005262 xmlXPathFreeObject(arg);
5263
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005264 CAST_TO_NUMBER;
5265 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005266 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5267 ctxt->value->floatval = xmlXPathNAN;
5268 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005269 if (ctxt->value->floatval == 0)
5270 ctxt->value->floatval = xmlXPathNAN;
5271 else if (ctxt->value->floatval > 0)
5272 ctxt->value->floatval = xmlXPathNINF;
5273 else if (ctxt->value->floatval < 0)
5274 ctxt->value->floatval = xmlXPathPINF;
5275 }
5276 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005277 if (ctxt->value->floatval == 0)
5278 ctxt->value->floatval = xmlXPathNAN;
5279 else if (ctxt->value->floatval > 0)
5280 ctxt->value->floatval = xmlXPathPINF;
5281 else if (ctxt->value->floatval < 0)
5282 ctxt->value->floatval = xmlXPathNINF;
5283 } else
5284 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005285}
5286
5287/**
5288 * xmlXPathModValues:
5289 * @ctxt: the XPath Parser context
5290 *
5291 * Implement the mod operation on XPath objects: @arg1 / @arg2
5292 * The numeric operators convert their operands to numbers as if
5293 * by calling the number function.
5294 */
5295void
5296xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5297 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005298 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005299
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005300 arg = valuePop(ctxt);
5301 if (arg == NULL)
5302 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005303 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005304 xmlXPathFreeObject(arg);
5305
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005306 CAST_TO_NUMBER;
5307 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005308 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005309 if (arg2 == 0)
5310 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005311 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005312 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005313 }
Owen Taylor3473f882001-02-23 17:55:21 +00005314}
5315
5316/************************************************************************
5317 * *
5318 * The traversal functions *
5319 * *
5320 ************************************************************************/
5321
Owen Taylor3473f882001-02-23 17:55:21 +00005322/*
5323 * A traversal function enumerates nodes along an axis.
5324 * Initially it must be called with NULL, and it indicates
5325 * termination on the axis by returning NULL.
5326 */
5327typedef xmlNodePtr (*xmlXPathTraversalFunction)
5328 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5329
5330/**
5331 * xmlXPathNextSelf:
5332 * @ctxt: the XPath Parser context
5333 * @cur: the current node in the traversal
5334 *
5335 * Traversal function for the "self" direction
5336 * The self axis contains just the context node itself
5337 *
5338 * Returns the next element following that axis
5339 */
5340xmlNodePtr
5341xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5342 if (cur == NULL)
5343 return(ctxt->context->node);
5344 return(NULL);
5345}
5346
5347/**
5348 * xmlXPathNextChild:
5349 * @ctxt: the XPath Parser context
5350 * @cur: the current node in the traversal
5351 *
5352 * Traversal function for the "child" direction
5353 * The child axis contains the children of the context node in document order.
5354 *
5355 * Returns the next element following that axis
5356 */
5357xmlNodePtr
5358xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5359 if (cur == NULL) {
5360 if (ctxt->context->node == NULL) return(NULL);
5361 switch (ctxt->context->node->type) {
5362 case XML_ELEMENT_NODE:
5363 case XML_TEXT_NODE:
5364 case XML_CDATA_SECTION_NODE:
5365 case XML_ENTITY_REF_NODE:
5366 case XML_ENTITY_NODE:
5367 case XML_PI_NODE:
5368 case XML_COMMENT_NODE:
5369 case XML_NOTATION_NODE:
5370 case XML_DTD_NODE:
5371 return(ctxt->context->node->children);
5372 case XML_DOCUMENT_NODE:
5373 case XML_DOCUMENT_TYPE_NODE:
5374 case XML_DOCUMENT_FRAG_NODE:
5375 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005376#ifdef LIBXML_DOCB_ENABLED
5377 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005378#endif
5379 return(((xmlDocPtr) ctxt->context->node)->children);
5380 case XML_ELEMENT_DECL:
5381 case XML_ATTRIBUTE_DECL:
5382 case XML_ENTITY_DECL:
5383 case XML_ATTRIBUTE_NODE:
5384 case XML_NAMESPACE_DECL:
5385 case XML_XINCLUDE_START:
5386 case XML_XINCLUDE_END:
5387 return(NULL);
5388 }
5389 return(NULL);
5390 }
5391 if ((cur->type == XML_DOCUMENT_NODE) ||
5392 (cur->type == XML_HTML_DOCUMENT_NODE))
5393 return(NULL);
5394 return(cur->next);
5395}
5396
5397/**
5398 * xmlXPathNextDescendant:
5399 * @ctxt: the XPath Parser context
5400 * @cur: the current node in the traversal
5401 *
5402 * Traversal function for the "descendant" direction
5403 * the descendant axis contains the descendants of the context node in document
5404 * order; a descendant is a child or a child of a child and so on.
5405 *
5406 * Returns the next element following that axis
5407 */
5408xmlNodePtr
5409xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5410 if (cur == NULL) {
5411 if (ctxt->context->node == NULL)
5412 return(NULL);
5413 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5414 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5415 return(NULL);
5416
5417 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5418 return(ctxt->context->doc->children);
5419 return(ctxt->context->node->children);
5420 }
5421
Daniel Veillard567e1b42001-08-01 15:53:47 +00005422 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005423 /*
5424 * Do not descend on entities declarations
5425 */
5426 if (cur->children->type != XML_ENTITY_DECL) {
5427 cur = cur->children;
5428 /*
5429 * Skip DTDs
5430 */
5431 if (cur->type != XML_DTD_NODE)
5432 return(cur);
5433 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005434 }
5435
5436 if (cur == ctxt->context->node) return(NULL);
5437
Daniel Veillard68e9e742002-11-16 15:35:11 +00005438 while (cur->next != NULL) {
5439 cur = cur->next;
5440 if ((cur->type != XML_ENTITY_DECL) &&
5441 (cur->type != XML_DTD_NODE))
5442 return(cur);
5443 }
Owen Taylor3473f882001-02-23 17:55:21 +00005444
5445 do {
5446 cur = cur->parent;
5447 if (cur == NULL) return(NULL);
5448 if (cur == ctxt->context->node) return(NULL);
5449 if (cur->next != NULL) {
5450 cur = cur->next;
5451 return(cur);
5452 }
5453 } while (cur != NULL);
5454 return(cur);
5455}
5456
5457/**
5458 * xmlXPathNextDescendantOrSelf:
5459 * @ctxt: the XPath Parser context
5460 * @cur: the current node in the traversal
5461 *
5462 * Traversal function for the "descendant-or-self" direction
5463 * the descendant-or-self axis contains the context node and the descendants
5464 * of the context node in document order; thus the context node is the first
5465 * node on the axis, and the first child of the context node is the second node
5466 * on the axis
5467 *
5468 * Returns the next element following that axis
5469 */
5470xmlNodePtr
5471xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5472 if (cur == NULL) {
5473 if (ctxt->context->node == NULL)
5474 return(NULL);
5475 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5476 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5477 return(NULL);
5478 return(ctxt->context->node);
5479 }
5480
5481 return(xmlXPathNextDescendant(ctxt, cur));
5482}
5483
5484/**
5485 * xmlXPathNextParent:
5486 * @ctxt: the XPath Parser context
5487 * @cur: the current node in the traversal
5488 *
5489 * Traversal function for the "parent" direction
5490 * The parent axis contains the parent of the context node, if there is one.
5491 *
5492 * Returns the next element following that axis
5493 */
5494xmlNodePtr
5495xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5496 /*
5497 * the parent of an attribute or namespace node is the element
5498 * to which the attribute or namespace node is attached
5499 * Namespace handling !!!
5500 */
5501 if (cur == NULL) {
5502 if (ctxt->context->node == NULL) return(NULL);
5503 switch (ctxt->context->node->type) {
5504 case XML_ELEMENT_NODE:
5505 case XML_TEXT_NODE:
5506 case XML_CDATA_SECTION_NODE:
5507 case XML_ENTITY_REF_NODE:
5508 case XML_ENTITY_NODE:
5509 case XML_PI_NODE:
5510 case XML_COMMENT_NODE:
5511 case XML_NOTATION_NODE:
5512 case XML_DTD_NODE:
5513 case XML_ELEMENT_DECL:
5514 case XML_ATTRIBUTE_DECL:
5515 case XML_XINCLUDE_START:
5516 case XML_XINCLUDE_END:
5517 case XML_ENTITY_DECL:
5518 if (ctxt->context->node->parent == NULL)
5519 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005520 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005521 ((ctxt->context->node->parent->name[0] == ' ') ||
5522 (xmlStrEqual(ctxt->context->node->parent->name,
5523 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005524 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005525 return(ctxt->context->node->parent);
5526 case XML_ATTRIBUTE_NODE: {
5527 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5528
5529 return(att->parent);
5530 }
5531 case XML_DOCUMENT_NODE:
5532 case XML_DOCUMENT_TYPE_NODE:
5533 case XML_DOCUMENT_FRAG_NODE:
5534 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005535#ifdef LIBXML_DOCB_ENABLED
5536 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005537#endif
5538 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005539 case XML_NAMESPACE_DECL: {
5540 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5541
5542 if ((ns->next != NULL) &&
5543 (ns->next->type != XML_NAMESPACE_DECL))
5544 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005545 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005546 }
Owen Taylor3473f882001-02-23 17:55:21 +00005547 }
5548 }
5549 return(NULL);
5550}
5551
5552/**
5553 * xmlXPathNextAncestor:
5554 * @ctxt: the XPath Parser context
5555 * @cur: the current node in the traversal
5556 *
5557 * Traversal function for the "ancestor" direction
5558 * the ancestor axis contains the ancestors of the context node; the ancestors
5559 * of the context node consist of the parent of context node and the parent's
5560 * parent and so on; the nodes are ordered in reverse document order; thus the
5561 * parent is the first node on the axis, and the parent's parent is the second
5562 * node on the axis
5563 *
5564 * Returns the next element following that axis
5565 */
5566xmlNodePtr
5567xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5568 /*
5569 * the parent of an attribute or namespace node is the element
5570 * to which the attribute or namespace node is attached
5571 * !!!!!!!!!!!!!
5572 */
5573 if (cur == NULL) {
5574 if (ctxt->context->node == NULL) return(NULL);
5575 switch (ctxt->context->node->type) {
5576 case XML_ELEMENT_NODE:
5577 case XML_TEXT_NODE:
5578 case XML_CDATA_SECTION_NODE:
5579 case XML_ENTITY_REF_NODE:
5580 case XML_ENTITY_NODE:
5581 case XML_PI_NODE:
5582 case XML_COMMENT_NODE:
5583 case XML_DTD_NODE:
5584 case XML_ELEMENT_DECL:
5585 case XML_ATTRIBUTE_DECL:
5586 case XML_ENTITY_DECL:
5587 case XML_NOTATION_NODE:
5588 case XML_XINCLUDE_START:
5589 case XML_XINCLUDE_END:
5590 if (ctxt->context->node->parent == NULL)
5591 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005592 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005593 ((ctxt->context->node->parent->name[0] == ' ') ||
5594 (xmlStrEqual(ctxt->context->node->parent->name,
5595 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005596 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005597 return(ctxt->context->node->parent);
5598 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005599 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005600
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005601 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005602 }
5603 case XML_DOCUMENT_NODE:
5604 case XML_DOCUMENT_TYPE_NODE:
5605 case XML_DOCUMENT_FRAG_NODE:
5606 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005607#ifdef LIBXML_DOCB_ENABLED
5608 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005609#endif
5610 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005611 case XML_NAMESPACE_DECL: {
5612 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5613
5614 if ((ns->next != NULL) &&
5615 (ns->next->type != XML_NAMESPACE_DECL))
5616 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005617 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005618 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005619 }
Owen Taylor3473f882001-02-23 17:55:21 +00005620 }
5621 return(NULL);
5622 }
5623 if (cur == ctxt->context->doc->children)
5624 return((xmlNodePtr) ctxt->context->doc);
5625 if (cur == (xmlNodePtr) ctxt->context->doc)
5626 return(NULL);
5627 switch (cur->type) {
5628 case XML_ELEMENT_NODE:
5629 case XML_TEXT_NODE:
5630 case XML_CDATA_SECTION_NODE:
5631 case XML_ENTITY_REF_NODE:
5632 case XML_ENTITY_NODE:
5633 case XML_PI_NODE:
5634 case XML_COMMENT_NODE:
5635 case XML_NOTATION_NODE:
5636 case XML_DTD_NODE:
5637 case XML_ELEMENT_DECL:
5638 case XML_ATTRIBUTE_DECL:
5639 case XML_ENTITY_DECL:
5640 case XML_XINCLUDE_START:
5641 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005642 if (cur->parent == NULL)
5643 return(NULL);
5644 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005645 ((cur->parent->name[0] == ' ') ||
5646 (xmlStrEqual(cur->parent->name,
5647 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005648 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005649 return(cur->parent);
5650 case XML_ATTRIBUTE_NODE: {
5651 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5652
5653 return(att->parent);
5654 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005655 case XML_NAMESPACE_DECL: {
5656 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5657
5658 if ((ns->next != NULL) &&
5659 (ns->next->type != XML_NAMESPACE_DECL))
5660 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005661 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005662 return(NULL);
5663 }
Owen Taylor3473f882001-02-23 17:55:21 +00005664 case XML_DOCUMENT_NODE:
5665 case XML_DOCUMENT_TYPE_NODE:
5666 case XML_DOCUMENT_FRAG_NODE:
5667 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005668#ifdef LIBXML_DOCB_ENABLED
5669 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005670#endif
5671 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005672 }
5673 return(NULL);
5674}
5675
5676/**
5677 * xmlXPathNextAncestorOrSelf:
5678 * @ctxt: the XPath Parser context
5679 * @cur: the current node in the traversal
5680 *
5681 * Traversal function for the "ancestor-or-self" direction
5682 * he ancestor-or-self axis contains the context node and ancestors of
5683 * the context node in reverse document order; thus the context node is
5684 * the first node on the axis, and the context node's parent the second;
5685 * parent here is defined the same as with the parent axis.
5686 *
5687 * Returns the next element following that axis
5688 */
5689xmlNodePtr
5690xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5691 if (cur == NULL)
5692 return(ctxt->context->node);
5693 return(xmlXPathNextAncestor(ctxt, cur));
5694}
5695
5696/**
5697 * xmlXPathNextFollowingSibling:
5698 * @ctxt: the XPath Parser context
5699 * @cur: the current node in the traversal
5700 *
5701 * Traversal function for the "following-sibling" direction
5702 * The following-sibling axis contains the following siblings of the context
5703 * node in document order.
5704 *
5705 * Returns the next element following that axis
5706 */
5707xmlNodePtr
5708xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5709 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5710 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5711 return(NULL);
5712 if (cur == (xmlNodePtr) ctxt->context->doc)
5713 return(NULL);
5714 if (cur == NULL)
5715 return(ctxt->context->node->next);
5716 return(cur->next);
5717}
5718
5719/**
5720 * xmlXPathNextPrecedingSibling:
5721 * @ctxt: the XPath Parser context
5722 * @cur: the current node in the traversal
5723 *
5724 * Traversal function for the "preceding-sibling" direction
5725 * The preceding-sibling axis contains the preceding siblings of the context
5726 * node in reverse document order; the first preceding sibling is first on the
5727 * axis; the sibling preceding that node is the second on the axis and so on.
5728 *
5729 * Returns the next element following that axis
5730 */
5731xmlNodePtr
5732xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5733 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5734 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5735 return(NULL);
5736 if (cur == (xmlNodePtr) ctxt->context->doc)
5737 return(NULL);
5738 if (cur == NULL)
5739 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005740 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5741 cur = cur->prev;
5742 if (cur == NULL)
5743 return(ctxt->context->node->prev);
5744 }
Owen Taylor3473f882001-02-23 17:55:21 +00005745 return(cur->prev);
5746}
5747
5748/**
5749 * xmlXPathNextFollowing:
5750 * @ctxt: the XPath Parser context
5751 * @cur: the current node in the traversal
5752 *
5753 * Traversal function for the "following" direction
5754 * The following axis contains all nodes in the same document as the context
5755 * node that are after the context node in document order, excluding any
5756 * descendants and excluding attribute nodes and namespace nodes; the nodes
5757 * are ordered in document order
5758 *
5759 * Returns the next element following that axis
5760 */
5761xmlNodePtr
5762xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5763 if (cur != NULL && cur->children != NULL)
5764 return cur->children ;
5765 if (cur == NULL) cur = ctxt->context->node;
5766 if (cur == NULL) return(NULL) ; /* ERROR */
5767 if (cur->next != NULL) return(cur->next) ;
5768 do {
5769 cur = cur->parent;
5770 if (cur == NULL) return(NULL);
5771 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5772 if (cur->next != NULL) return(cur->next);
5773 } while (cur != NULL);
5774 return(cur);
5775}
5776
5777/*
5778 * xmlXPathIsAncestor:
5779 * @ancestor: the ancestor node
5780 * @node: the current node
5781 *
5782 * Check that @ancestor is a @node's ancestor
5783 *
5784 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5785 */
5786static int
5787xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5788 if ((ancestor == NULL) || (node == NULL)) return(0);
5789 /* nodes need to be in the same document */
5790 if (ancestor->doc != node->doc) return(0);
5791 /* avoid searching if ancestor or node is the root node */
5792 if (ancestor == (xmlNodePtr) node->doc) return(1);
5793 if (node == (xmlNodePtr) ancestor->doc) return(0);
5794 while (node->parent != NULL) {
5795 if (node->parent == ancestor)
5796 return(1);
5797 node = node->parent;
5798 }
5799 return(0);
5800}
5801
5802/**
5803 * xmlXPathNextPreceding:
5804 * @ctxt: the XPath Parser context
5805 * @cur: the current node in the traversal
5806 *
5807 * Traversal function for the "preceding" direction
5808 * the preceding axis contains all nodes in the same document as the context
5809 * node that are before the context node in document order, excluding any
5810 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5811 * ordered in reverse document order
5812 *
5813 * Returns the next element following that axis
5814 */
5815xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005816xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5817{
Owen Taylor3473f882001-02-23 17:55:21 +00005818 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005819 cur = ctxt->context->node;
5820 if (cur == NULL)
5821 return (NULL);
5822 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5823 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005824 do {
5825 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005826 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5827 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005828 }
5829
5830 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005831 if (cur == NULL)
5832 return (NULL);
5833 if (cur == ctxt->context->doc->children)
5834 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005835 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005836 return (cur);
5837}
5838
5839/**
5840 * xmlXPathNextPrecedingInternal:
5841 * @ctxt: the XPath Parser context
5842 * @cur: the current node in the traversal
5843 *
5844 * Traversal function for the "preceding" direction
5845 * the preceding axis contains all nodes in the same document as the context
5846 * node that are before the context node in document order, excluding any
5847 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5848 * ordered in reverse document order
5849 * This is a faster implementation but internal only since it requires a
5850 * state kept in the parser context: ctxt->ancestor.
5851 *
5852 * Returns the next element following that axis
5853 */
5854static xmlNodePtr
5855xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5856 xmlNodePtr cur)
5857{
5858 if (cur == NULL) {
5859 cur = ctxt->context->node;
5860 if (cur == NULL)
5861 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005862 if (cur->type == XML_NAMESPACE_DECL)
5863 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005864 ctxt->ancestor = cur->parent;
5865 }
5866 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5867 cur = cur->prev;
5868 while (cur->prev == NULL) {
5869 cur = cur->parent;
5870 if (cur == NULL)
5871 return (NULL);
5872 if (cur == ctxt->context->doc->children)
5873 return (NULL);
5874 if (cur != ctxt->ancestor)
5875 return (cur);
5876 ctxt->ancestor = cur->parent;
5877 }
5878 cur = cur->prev;
5879 while (cur->last != NULL)
5880 cur = cur->last;
5881 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005882}
5883
5884/**
5885 * xmlXPathNextNamespace:
5886 * @ctxt: the XPath Parser context
5887 * @cur: the current attribute in the traversal
5888 *
5889 * Traversal function for the "namespace" direction
5890 * the namespace axis contains the namespace nodes of the context node;
5891 * the order of nodes on this axis is implementation-defined; the axis will
5892 * be empty unless the context node is an element
5893 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005894 * We keep the XML namespace node at the end of the list.
5895 *
Owen Taylor3473f882001-02-23 17:55:21 +00005896 * Returns the next element following that axis
5897 */
5898xmlNodePtr
5899xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5900 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005901 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005902 if (ctxt->context->tmpNsList != NULL)
5903 xmlFree(ctxt->context->tmpNsList);
5904 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005905 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005906 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005907 if (ctxt->context->tmpNsList != NULL) {
5908 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5909 ctxt->context->tmpNsNr++;
5910 }
5911 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005912 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005913 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005914 if (ctxt->context->tmpNsNr > 0) {
5915 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5916 } else {
5917 if (ctxt->context->tmpNsList != NULL)
5918 xmlFree(ctxt->context->tmpNsList);
5919 ctxt->context->tmpNsList = NULL;
5920 return(NULL);
5921 }
Owen Taylor3473f882001-02-23 17:55:21 +00005922}
5923
5924/**
5925 * xmlXPathNextAttribute:
5926 * @ctxt: the XPath Parser context
5927 * @cur: the current attribute in the traversal
5928 *
5929 * Traversal function for the "attribute" direction
5930 * TODO: support DTD inherited default attributes
5931 *
5932 * Returns the next element following that axis
5933 */
5934xmlNodePtr
5935xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005936 if (ctxt->context->node == NULL)
5937 return(NULL);
5938 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5939 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005940 if (cur == NULL) {
5941 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5942 return(NULL);
5943 return((xmlNodePtr)ctxt->context->node->properties);
5944 }
5945 return((xmlNodePtr)cur->next);
5946}
5947
5948/************************************************************************
5949 * *
5950 * NodeTest Functions *
5951 * *
5952 ************************************************************************/
5953
Owen Taylor3473f882001-02-23 17:55:21 +00005954#define IS_FUNCTION 200
5955
Owen Taylor3473f882001-02-23 17:55:21 +00005956
5957/************************************************************************
5958 * *
5959 * Implicit tree core function library *
5960 * *
5961 ************************************************************************/
5962
5963/**
5964 * xmlXPathRoot:
5965 * @ctxt: the XPath Parser context
5966 *
5967 * Initialize the context to the root of the document
5968 */
5969void
5970xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5971 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5972 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5973}
5974
5975/************************************************************************
5976 * *
5977 * The explicit core function library *
5978 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5979 * *
5980 ************************************************************************/
5981
5982
5983/**
5984 * xmlXPathLastFunction:
5985 * @ctxt: the XPath Parser context
5986 * @nargs: the number of arguments
5987 *
5988 * Implement the last() XPath function
5989 * number last()
5990 * The last function returns the number of nodes in the context node list.
5991 */
5992void
5993xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5994 CHECK_ARITY(0);
5995 if (ctxt->context->contextSize >= 0) {
5996 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5997#ifdef DEBUG_EXPR
5998 xmlGenericError(xmlGenericErrorContext,
5999 "last() : %d\n", ctxt->context->contextSize);
6000#endif
6001 } else {
6002 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6003 }
6004}
6005
6006/**
6007 * xmlXPathPositionFunction:
6008 * @ctxt: the XPath Parser context
6009 * @nargs: the number of arguments
6010 *
6011 * Implement the position() XPath function
6012 * number position()
6013 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006014 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00006015 * will be equal to last().
6016 */
6017void
6018xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6019 CHECK_ARITY(0);
6020 if (ctxt->context->proximityPosition >= 0) {
6021 valuePush(ctxt,
6022 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6023#ifdef DEBUG_EXPR
6024 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6025 ctxt->context->proximityPosition);
6026#endif
6027 } else {
6028 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6029 }
6030}
6031
6032/**
6033 * xmlXPathCountFunction:
6034 * @ctxt: the XPath Parser context
6035 * @nargs: the number of arguments
6036 *
6037 * Implement the count() XPath function
6038 * number count(node-set)
6039 */
6040void
6041xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6042 xmlXPathObjectPtr cur;
6043
6044 CHECK_ARITY(1);
6045 if ((ctxt->value == NULL) ||
6046 ((ctxt->value->type != XPATH_NODESET) &&
6047 (ctxt->value->type != XPATH_XSLT_TREE)))
6048 XP_ERROR(XPATH_INVALID_TYPE);
6049 cur = valuePop(ctxt);
6050
Daniel Veillard911f49a2001-04-07 15:39:35 +00006051 if ((cur == NULL) || (cur->nodesetval == NULL))
6052 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006053 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006054 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006055 } else {
6056 if ((cur->nodesetval->nodeNr != 1) ||
6057 (cur->nodesetval->nodeTab == NULL)) {
6058 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6059 } else {
6060 xmlNodePtr tmp;
6061 int i = 0;
6062
6063 tmp = cur->nodesetval->nodeTab[0];
6064 if (tmp != NULL) {
6065 tmp = tmp->children;
6066 while (tmp != NULL) {
6067 tmp = tmp->next;
6068 i++;
6069 }
6070 }
6071 valuePush(ctxt, xmlXPathNewFloat((double) i));
6072 }
6073 }
Owen Taylor3473f882001-02-23 17:55:21 +00006074 xmlXPathFreeObject(cur);
6075}
6076
6077/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006078 * xmlXPathGetElementsByIds:
6079 * @doc: the document
6080 * @ids: a whitespace separated list of IDs
6081 *
6082 * Selects elements by their unique ID.
6083 *
6084 * Returns a node-set of selected elements.
6085 */
6086static xmlNodeSetPtr
6087xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6088 xmlNodeSetPtr ret;
6089 const xmlChar *cur = ids;
6090 xmlChar *ID;
6091 xmlAttrPtr attr;
6092 xmlNodePtr elem = NULL;
6093
Daniel Veillard7a985a12003-07-06 17:57:42 +00006094 if (ids == NULL) return(NULL);
6095
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006096 ret = xmlXPathNodeSetCreate(NULL);
6097
William M. Brack76e95df2003-10-18 16:20:14 +00006098 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006099 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006100 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006101 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006102
6103 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006104 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00006105 /*
6106 * We used to check the fact that the value passed
6107 * was an NCName, but this generated much troubles for
6108 * me and Aleksey Sanin, people blatantly violated that
6109 * constaint, like Visa3D spec.
6110 * if (xmlValidateNCName(ID, 1) == 0)
6111 */
6112 attr = xmlGetID(doc, ID);
6113 if (attr != NULL) {
6114 if (attr->type == XML_ATTRIBUTE_NODE)
6115 elem = attr->parent;
6116 else if (attr->type == XML_ELEMENT_NODE)
6117 elem = (xmlNodePtr) attr;
6118 else
6119 elem = NULL;
6120 if (elem != NULL)
6121 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00006122 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006123 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006124 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006125
William M. Brack76e95df2003-10-18 16:20:14 +00006126 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006127 ids = cur;
6128 }
6129 return(ret);
6130}
6131
6132/**
Owen Taylor3473f882001-02-23 17:55:21 +00006133 * xmlXPathIdFunction:
6134 * @ctxt: the XPath Parser context
6135 * @nargs: the number of arguments
6136 *
6137 * Implement the id() XPath function
6138 * node-set id(object)
6139 * The id function selects elements by their unique ID
6140 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6141 * then the result is the union of the result of applying id to the
6142 * string value of each of the nodes in the argument node-set. When the
6143 * argument to id is of any other type, the argument is converted to a
6144 * string as if by a call to the string function; the string is split
6145 * into a whitespace-separated list of tokens (whitespace is any sequence
6146 * of characters matching the production S); the result is a node-set
6147 * containing the elements in the same document as the context node that
6148 * have a unique ID equal to any of the tokens in the list.
6149 */
6150void
6151xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006152 xmlChar *tokens;
6153 xmlNodeSetPtr ret;
6154 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006155
6156 CHECK_ARITY(1);
6157 obj = valuePop(ctxt);
6158 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006159 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006160 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006161 int i;
6162
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006163 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006164
Daniel Veillard911f49a2001-04-07 15:39:35 +00006165 if (obj->nodesetval != NULL) {
6166 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006167 tokens =
6168 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6169 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6170 ret = xmlXPathNodeSetMerge(ret, ns);
6171 xmlXPathFreeNodeSet(ns);
6172 if (tokens != NULL)
6173 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006174 }
Owen Taylor3473f882001-02-23 17:55:21 +00006175 }
6176
6177 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006178 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006179 return;
6180 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006181 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006182
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006183 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6184 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006185
Owen Taylor3473f882001-02-23 17:55:21 +00006186 xmlXPathFreeObject(obj);
6187 return;
6188}
6189
6190/**
6191 * xmlXPathLocalNameFunction:
6192 * @ctxt: the XPath Parser context
6193 * @nargs: the number of arguments
6194 *
6195 * Implement the local-name() XPath function
6196 * string local-name(node-set?)
6197 * The local-name function returns a string containing the local part
6198 * of the name of the node in the argument node-set that is first in
6199 * document order. If the node-set is empty or the first node has no
6200 * name, an empty string is returned. If the argument is omitted it
6201 * defaults to the context node.
6202 */
6203void
6204xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6205 xmlXPathObjectPtr cur;
6206
6207 if (nargs == 0) {
6208 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6209 nargs = 1;
6210 }
6211
6212 CHECK_ARITY(1);
6213 if ((ctxt->value == NULL) ||
6214 ((ctxt->value->type != XPATH_NODESET) &&
6215 (ctxt->value->type != XPATH_XSLT_TREE)))
6216 XP_ERROR(XPATH_INVALID_TYPE);
6217 cur = valuePop(ctxt);
6218
Daniel Veillard911f49a2001-04-07 15:39:35 +00006219 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006220 valuePush(ctxt, xmlXPathNewCString(""));
6221 } else {
6222 int i = 0; /* Should be first in document order !!!!! */
6223 switch (cur->nodesetval->nodeTab[i]->type) {
6224 case XML_ELEMENT_NODE:
6225 case XML_ATTRIBUTE_NODE:
6226 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006227 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6228 valuePush(ctxt, xmlXPathNewCString(""));
6229 else
6230 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006231 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6232 break;
6233 case XML_NAMESPACE_DECL:
6234 valuePush(ctxt, xmlXPathNewString(
6235 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6236 break;
6237 default:
6238 valuePush(ctxt, xmlXPathNewCString(""));
6239 }
6240 }
6241 xmlXPathFreeObject(cur);
6242}
6243
6244/**
6245 * xmlXPathNamespaceURIFunction:
6246 * @ctxt: the XPath Parser context
6247 * @nargs: the number of arguments
6248 *
6249 * Implement the namespace-uri() XPath function
6250 * string namespace-uri(node-set?)
6251 * The namespace-uri function returns a string containing the
6252 * namespace URI of the expanded name of the node in the argument
6253 * node-set that is first in document order. If the node-set is empty,
6254 * the first node has no name, or the expanded name has no namespace
6255 * URI, an empty string is returned. If the argument is omitted it
6256 * defaults to the context node.
6257 */
6258void
6259xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6260 xmlXPathObjectPtr cur;
6261
6262 if (nargs == 0) {
6263 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6264 nargs = 1;
6265 }
6266 CHECK_ARITY(1);
6267 if ((ctxt->value == NULL) ||
6268 ((ctxt->value->type != XPATH_NODESET) &&
6269 (ctxt->value->type != XPATH_XSLT_TREE)))
6270 XP_ERROR(XPATH_INVALID_TYPE);
6271 cur = valuePop(ctxt);
6272
Daniel Veillard911f49a2001-04-07 15:39:35 +00006273 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006274 valuePush(ctxt, xmlXPathNewCString(""));
6275 } else {
6276 int i = 0; /* Should be first in document order !!!!! */
6277 switch (cur->nodesetval->nodeTab[i]->type) {
6278 case XML_ELEMENT_NODE:
6279 case XML_ATTRIBUTE_NODE:
6280 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6281 valuePush(ctxt, xmlXPathNewCString(""));
6282 else
6283 valuePush(ctxt, xmlXPathNewString(
6284 cur->nodesetval->nodeTab[i]->ns->href));
6285 break;
6286 default:
6287 valuePush(ctxt, xmlXPathNewCString(""));
6288 }
6289 }
6290 xmlXPathFreeObject(cur);
6291}
6292
6293/**
6294 * xmlXPathNameFunction:
6295 * @ctxt: the XPath Parser context
6296 * @nargs: the number of arguments
6297 *
6298 * Implement the name() XPath function
6299 * string name(node-set?)
6300 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006301 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006302 * order. The QName must represent the name with respect to the namespace
6303 * declarations in effect on the node whose name is being represented.
6304 * Typically, this will be the form in which the name occurred in the XML
6305 * source. This need not be the case if there are namespace declarations
6306 * in effect on the node that associate multiple prefixes with the same
6307 * namespace. However, an implementation may include information about
6308 * the original prefix in its representation of nodes; in this case, an
6309 * implementation can ensure that the returned string is always the same
6310 * as the QName used in the XML source. If the argument it omitted it
6311 * defaults to the context node.
6312 * Libxml keep the original prefix so the "real qualified name" used is
6313 * returned.
6314 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006315static void
Daniel Veillard04383752001-07-08 14:27:15 +00006316xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6317{
Owen Taylor3473f882001-02-23 17:55:21 +00006318 xmlXPathObjectPtr cur;
6319
6320 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006321 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6322 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006323 }
6324
6325 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006326 if ((ctxt->value == NULL) ||
6327 ((ctxt->value->type != XPATH_NODESET) &&
6328 (ctxt->value->type != XPATH_XSLT_TREE)))
6329 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006330 cur = valuePop(ctxt);
6331
Daniel Veillard911f49a2001-04-07 15:39:35 +00006332 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006333 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006334 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006335 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006336
Daniel Veillard04383752001-07-08 14:27:15 +00006337 switch (cur->nodesetval->nodeTab[i]->type) {
6338 case XML_ELEMENT_NODE:
6339 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006340 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6341 valuePush(ctxt, xmlXPathNewCString(""));
6342 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6343 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006344 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006345 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006346
Daniel Veillard652d8a92003-02-04 19:28:49 +00006347 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006348 xmlChar *fullname;
6349
6350 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6351 cur->nodesetval->nodeTab[i]->ns->prefix,
6352 NULL, 0);
6353 if (fullname == cur->nodesetval->nodeTab[i]->name)
6354 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6355 if (fullname == NULL) {
6356 XP_ERROR(XPATH_MEMORY_ERROR);
6357 }
6358 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006359 }
6360 break;
6361 default:
6362 valuePush(ctxt,
6363 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6364 xmlXPathLocalNameFunction(ctxt, 1);
6365 }
Owen Taylor3473f882001-02-23 17:55:21 +00006366 }
6367 xmlXPathFreeObject(cur);
6368}
6369
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006370
6371/**
Owen Taylor3473f882001-02-23 17:55:21 +00006372 * xmlXPathStringFunction:
6373 * @ctxt: the XPath Parser context
6374 * @nargs: the number of arguments
6375 *
6376 * Implement the string() XPath function
6377 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006378 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006379 * - A node-set is converted to a string by returning the value of
6380 * the node in the node-set that is first in document order.
6381 * If the node-set is empty, an empty string is returned.
6382 * - A number is converted to a string as follows
6383 * + NaN is converted to the string NaN
6384 * + positive zero is converted to the string 0
6385 * + negative zero is converted to the string 0
6386 * + positive infinity is converted to the string Infinity
6387 * + negative infinity is converted to the string -Infinity
6388 * + if the number is an integer, the number is represented in
6389 * decimal form as a Number with no decimal point and no leading
6390 * zeros, preceded by a minus sign (-) if the number is negative
6391 * + otherwise, the number is represented in decimal form as a
6392 * Number including a decimal point with at least one digit
6393 * before the decimal point and at least one digit after the
6394 * decimal point, preceded by a minus sign (-) if the number
6395 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006396 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006397 * before the decimal point; beyond the one required digit
6398 * after the decimal point there must be as many, but only as
6399 * many, more digits as are needed to uniquely distinguish the
6400 * number from all other IEEE 754 numeric values.
6401 * - The boolean false value is converted to the string false.
6402 * The boolean true value is converted to the string true.
6403 *
6404 * If the argument is omitted, it defaults to a node-set with the
6405 * context node as its only member.
6406 */
6407void
6408xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6409 xmlXPathObjectPtr cur;
6410
6411 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006412 valuePush(ctxt,
6413 xmlXPathWrapString(
6414 xmlXPathCastNodeToString(ctxt->context->node)));
6415 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006416 }
6417
6418 CHECK_ARITY(1);
6419 cur = valuePop(ctxt);
6420 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006421 cur = xmlXPathConvertString(cur);
6422 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006423}
6424
6425/**
6426 * xmlXPathStringLengthFunction:
6427 * @ctxt: the XPath Parser context
6428 * @nargs: the number of arguments
6429 *
6430 * Implement the string-length() XPath function
6431 * number string-length(string?)
6432 * The string-length returns the number of characters in the string
6433 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6434 * the context node converted to a string, in other words the value
6435 * of the context node.
6436 */
6437void
6438xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6439 xmlXPathObjectPtr cur;
6440
6441 if (nargs == 0) {
6442 if (ctxt->context->node == NULL) {
6443 valuePush(ctxt, xmlXPathNewFloat(0));
6444 } else {
6445 xmlChar *content;
6446
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006447 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006448 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006449 xmlFree(content);
6450 }
6451 return;
6452 }
6453 CHECK_ARITY(1);
6454 CAST_TO_STRING;
6455 CHECK_TYPE(XPATH_STRING);
6456 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006457 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006458 xmlXPathFreeObject(cur);
6459}
6460
6461/**
6462 * xmlXPathConcatFunction:
6463 * @ctxt: the XPath Parser context
6464 * @nargs: the number of arguments
6465 *
6466 * Implement the concat() XPath function
6467 * string concat(string, string, string*)
6468 * The concat function returns the concatenation of its arguments.
6469 */
6470void
6471xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6472 xmlXPathObjectPtr cur, newobj;
6473 xmlChar *tmp;
6474
6475 if (nargs < 2) {
6476 CHECK_ARITY(2);
6477 }
6478
6479 CAST_TO_STRING;
6480 cur = valuePop(ctxt);
6481 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6482 xmlXPathFreeObject(cur);
6483 return;
6484 }
6485 nargs--;
6486
6487 while (nargs > 0) {
6488 CAST_TO_STRING;
6489 newobj = valuePop(ctxt);
6490 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6491 xmlXPathFreeObject(newobj);
6492 xmlXPathFreeObject(cur);
6493 XP_ERROR(XPATH_INVALID_TYPE);
6494 }
6495 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6496 newobj->stringval = cur->stringval;
6497 cur->stringval = tmp;
6498
6499 xmlXPathFreeObject(newobj);
6500 nargs--;
6501 }
6502 valuePush(ctxt, cur);
6503}
6504
6505/**
6506 * xmlXPathContainsFunction:
6507 * @ctxt: the XPath Parser context
6508 * @nargs: the number of arguments
6509 *
6510 * Implement the contains() XPath function
6511 * boolean contains(string, string)
6512 * The contains function returns true if the first argument string
6513 * contains the second argument string, and otherwise returns false.
6514 */
6515void
6516xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6517 xmlXPathObjectPtr hay, needle;
6518
6519 CHECK_ARITY(2);
6520 CAST_TO_STRING;
6521 CHECK_TYPE(XPATH_STRING);
6522 needle = valuePop(ctxt);
6523 CAST_TO_STRING;
6524 hay = valuePop(ctxt);
6525 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6526 xmlXPathFreeObject(hay);
6527 xmlXPathFreeObject(needle);
6528 XP_ERROR(XPATH_INVALID_TYPE);
6529 }
6530 if (xmlStrstr(hay->stringval, needle->stringval))
6531 valuePush(ctxt, xmlXPathNewBoolean(1));
6532 else
6533 valuePush(ctxt, xmlXPathNewBoolean(0));
6534 xmlXPathFreeObject(hay);
6535 xmlXPathFreeObject(needle);
6536}
6537
6538/**
6539 * xmlXPathStartsWithFunction:
6540 * @ctxt: the XPath Parser context
6541 * @nargs: the number of arguments
6542 *
6543 * Implement the starts-with() XPath function
6544 * boolean starts-with(string, string)
6545 * The starts-with function returns true if the first argument string
6546 * starts with the second argument string, and otherwise returns false.
6547 */
6548void
6549xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6550 xmlXPathObjectPtr hay, needle;
6551 int n;
6552
6553 CHECK_ARITY(2);
6554 CAST_TO_STRING;
6555 CHECK_TYPE(XPATH_STRING);
6556 needle = valuePop(ctxt);
6557 CAST_TO_STRING;
6558 hay = valuePop(ctxt);
6559 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6560 xmlXPathFreeObject(hay);
6561 xmlXPathFreeObject(needle);
6562 XP_ERROR(XPATH_INVALID_TYPE);
6563 }
6564 n = xmlStrlen(needle->stringval);
6565 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6566 valuePush(ctxt, xmlXPathNewBoolean(0));
6567 else
6568 valuePush(ctxt, xmlXPathNewBoolean(1));
6569 xmlXPathFreeObject(hay);
6570 xmlXPathFreeObject(needle);
6571}
6572
6573/**
6574 * xmlXPathSubstringFunction:
6575 * @ctxt: the XPath Parser context
6576 * @nargs: the number of arguments
6577 *
6578 * Implement the substring() XPath function
6579 * string substring(string, number, number?)
6580 * The substring function returns the substring of the first argument
6581 * starting at the position specified in the second argument with
6582 * length specified in the third argument. For example,
6583 * substring("12345",2,3) returns "234". If the third argument is not
6584 * specified, it returns the substring starting at the position specified
6585 * in the second argument and continuing to the end of the string. For
6586 * example, substring("12345",2) returns "2345". More precisely, each
6587 * character in the string (see [3.6 Strings]) is considered to have a
6588 * numeric position: the position of the first character is 1, the position
6589 * of the second character is 2 and so on. The returned substring contains
6590 * those characters for which the position of the character is greater than
6591 * or equal to the second argument and, if the third argument is specified,
6592 * less than the sum of the second and third arguments; the comparisons
6593 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6594 * - substring("12345", 1.5, 2.6) returns "234"
6595 * - substring("12345", 0, 3) returns "12"
6596 * - substring("12345", 0 div 0, 3) returns ""
6597 * - substring("12345", 1, 0 div 0) returns ""
6598 * - substring("12345", -42, 1 div 0) returns "12345"
6599 * - substring("12345", -1 div 0, 1 div 0) returns ""
6600 */
6601void
6602xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6603 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006604 double le=0, in;
6605 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006606 xmlChar *ret;
6607
Owen Taylor3473f882001-02-23 17:55:21 +00006608 if (nargs < 2) {
6609 CHECK_ARITY(2);
6610 }
6611 if (nargs > 3) {
6612 CHECK_ARITY(3);
6613 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006614 /*
6615 * take care of possible last (position) argument
6616 */
Owen Taylor3473f882001-02-23 17:55:21 +00006617 if (nargs == 3) {
6618 CAST_TO_NUMBER;
6619 CHECK_TYPE(XPATH_NUMBER);
6620 len = valuePop(ctxt);
6621 le = len->floatval;
6622 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006623 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006624
Owen Taylor3473f882001-02-23 17:55:21 +00006625 CAST_TO_NUMBER;
6626 CHECK_TYPE(XPATH_NUMBER);
6627 start = valuePop(ctxt);
6628 in = start->floatval;
6629 xmlXPathFreeObject(start);
6630 CAST_TO_STRING;
6631 CHECK_TYPE(XPATH_STRING);
6632 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006633 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006634
Daniel Veillard97ac1312001-05-30 19:14:17 +00006635 /*
6636 * If last pos not present, calculate last position
6637 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006638 if (nargs != 3) {
6639 le = (double)m;
6640 if (in < 1.0)
6641 in = 1.0;
6642 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006643
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006644 /* Need to check for the special cases where either
6645 * the index is NaN, the length is NaN, or both
6646 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006647 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006648 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006649 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006650 * To meet the requirements of the spec, the arguments
6651 * must be converted to integer format before
6652 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006653 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006654 * First we go to integer form, rounding up
6655 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006656 */
6657 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006658 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006659
Daniel Veillard9e412302002-06-10 15:59:44 +00006660 if (xmlXPathIsInf(le) == 1) {
6661 l = m;
6662 if (i < 1)
6663 i = 1;
6664 }
6665 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6666 l = 0;
6667 else {
6668 l = (int) le;
6669 if (((double)l)+0.5 <= le) l++;
6670 }
6671
6672 /* Now we normalize inidices */
6673 i -= 1;
6674 l += i;
6675 if (i < 0)
6676 i = 0;
6677 if (l > m)
6678 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006679
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006680 /* number of chars to copy */
6681 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006682
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006683 ret = xmlUTF8Strsub(str->stringval, i, l);
6684 }
6685 else {
6686 ret = NULL;
6687 }
6688
Owen Taylor3473f882001-02-23 17:55:21 +00006689 if (ret == NULL)
6690 valuePush(ctxt, xmlXPathNewCString(""));
6691 else {
6692 valuePush(ctxt, xmlXPathNewString(ret));
6693 xmlFree(ret);
6694 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006695
Owen Taylor3473f882001-02-23 17:55:21 +00006696 xmlXPathFreeObject(str);
6697}
6698
6699/**
6700 * xmlXPathSubstringBeforeFunction:
6701 * @ctxt: the XPath Parser context
6702 * @nargs: the number of arguments
6703 *
6704 * Implement the substring-before() XPath function
6705 * string substring-before(string, string)
6706 * The substring-before function returns the substring of the first
6707 * argument string that precedes the first occurrence of the second
6708 * argument string in the first argument string, or the empty string
6709 * if the first argument string does not contain the second argument
6710 * string. For example, substring-before("1999/04/01","/") returns 1999.
6711 */
6712void
6713xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6714 xmlXPathObjectPtr str;
6715 xmlXPathObjectPtr find;
6716 xmlBufferPtr target;
6717 const xmlChar *point;
6718 int offset;
6719
6720 CHECK_ARITY(2);
6721 CAST_TO_STRING;
6722 find = valuePop(ctxt);
6723 CAST_TO_STRING;
6724 str = valuePop(ctxt);
6725
6726 target = xmlBufferCreate();
6727 if (target) {
6728 point = xmlStrstr(str->stringval, find->stringval);
6729 if (point) {
6730 offset = (int)(point - str->stringval);
6731 xmlBufferAdd(target, str->stringval, offset);
6732 }
6733 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6734 xmlBufferFree(target);
6735 }
6736
6737 xmlXPathFreeObject(str);
6738 xmlXPathFreeObject(find);
6739}
6740
6741/**
6742 * xmlXPathSubstringAfterFunction:
6743 * @ctxt: the XPath Parser context
6744 * @nargs: the number of arguments
6745 *
6746 * Implement the substring-after() XPath function
6747 * string substring-after(string, string)
6748 * The substring-after function returns the substring of the first
6749 * argument string that follows the first occurrence of the second
6750 * argument string in the first argument string, or the empty stringi
6751 * if the first argument string does not contain the second argument
6752 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6753 * and substring-after("1999/04/01","19") returns 99/04/01.
6754 */
6755void
6756xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6757 xmlXPathObjectPtr str;
6758 xmlXPathObjectPtr find;
6759 xmlBufferPtr target;
6760 const xmlChar *point;
6761 int offset;
6762
6763 CHECK_ARITY(2);
6764 CAST_TO_STRING;
6765 find = valuePop(ctxt);
6766 CAST_TO_STRING;
6767 str = valuePop(ctxt);
6768
6769 target = xmlBufferCreate();
6770 if (target) {
6771 point = xmlStrstr(str->stringval, find->stringval);
6772 if (point) {
6773 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6774 xmlBufferAdd(target, &str->stringval[offset],
6775 xmlStrlen(str->stringval) - offset);
6776 }
6777 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6778 xmlBufferFree(target);
6779 }
6780
6781 xmlXPathFreeObject(str);
6782 xmlXPathFreeObject(find);
6783}
6784
6785/**
6786 * xmlXPathNormalizeFunction:
6787 * @ctxt: the XPath Parser context
6788 * @nargs: the number of arguments
6789 *
6790 * Implement the normalize-space() XPath function
6791 * string normalize-space(string?)
6792 * The normalize-space function returns the argument string with white
6793 * space normalized by stripping leading and trailing whitespace
6794 * and replacing sequences of whitespace characters by a single
6795 * space. Whitespace characters are the same allowed by the S production
6796 * in XML. If the argument is omitted, it defaults to the context
6797 * node converted to a string, in other words the value of the context node.
6798 */
6799void
6800xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6801 xmlXPathObjectPtr obj = NULL;
6802 xmlChar *source = NULL;
6803 xmlBufferPtr target;
6804 xmlChar blank;
6805
6806 if (nargs == 0) {
6807 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006808 valuePush(ctxt,
6809 xmlXPathWrapString(
6810 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006811 nargs = 1;
6812 }
6813
6814 CHECK_ARITY(1);
6815 CAST_TO_STRING;
6816 CHECK_TYPE(XPATH_STRING);
6817 obj = valuePop(ctxt);
6818 source = obj->stringval;
6819
6820 target = xmlBufferCreate();
6821 if (target && source) {
6822
6823 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006824 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006825 source++;
6826
6827 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6828 blank = 0;
6829 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006830 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006831 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006832 } else {
6833 if (blank) {
6834 xmlBufferAdd(target, &blank, 1);
6835 blank = 0;
6836 }
6837 xmlBufferAdd(target, source, 1);
6838 }
6839 source++;
6840 }
6841
6842 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6843 xmlBufferFree(target);
6844 }
6845 xmlXPathFreeObject(obj);
6846}
6847
6848/**
6849 * xmlXPathTranslateFunction:
6850 * @ctxt: the XPath Parser context
6851 * @nargs: the number of arguments
6852 *
6853 * Implement the translate() XPath function
6854 * string translate(string, string, string)
6855 * The translate function returns the first argument string with
6856 * occurrences of characters in the second argument string replaced
6857 * by the character at the corresponding position in the third argument
6858 * string. For example, translate("bar","abc","ABC") returns the string
6859 * BAr. If there is a character in the second argument string with no
6860 * character at a corresponding position in the third argument string
6861 * (because the second argument string is longer than the third argument
6862 * string), then occurrences of that character in the first argument
6863 * string are removed. For example, translate("--aaa--","abc-","ABC")
6864 * returns "AAA". If a character occurs more than once in second
6865 * argument string, then the first occurrence determines the replacement
6866 * character. If the third argument string is longer than the second
6867 * argument string, then excess characters are ignored.
6868 */
6869void
6870xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006871 xmlXPathObjectPtr str;
6872 xmlXPathObjectPtr from;
6873 xmlXPathObjectPtr to;
6874 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006875 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006876 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00006877 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006878 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006879
Daniel Veillarde043ee12001-04-16 14:08:07 +00006880 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006881
Daniel Veillarde043ee12001-04-16 14:08:07 +00006882 CAST_TO_STRING;
6883 to = valuePop(ctxt);
6884 CAST_TO_STRING;
6885 from = valuePop(ctxt);
6886 CAST_TO_STRING;
6887 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006888
Daniel Veillarde043ee12001-04-16 14:08:07 +00006889 target = xmlBufferCreate();
6890 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006891 max = xmlUTF8Strlen(to->stringval);
6892 for (cptr = str->stringval; (ch=*cptr); ) {
6893 offset = xmlUTF8Strloc(from->stringval, cptr);
6894 if (offset >= 0) {
6895 if (offset < max) {
6896 point = xmlUTF8Strpos(to->stringval, offset);
6897 if (point)
6898 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6899 }
6900 } else
6901 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6902
6903 /* Step to next character in input */
6904 cptr++;
6905 if ( ch & 0x80 ) {
6906 /* if not simple ascii, verify proper format */
6907 if ( (ch & 0xc0) != 0xc0 ) {
6908 xmlGenericError(xmlGenericErrorContext,
6909 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6910 break;
6911 }
6912 /* then skip over remaining bytes for this char */
6913 while ( (ch <<= 1) & 0x80 )
6914 if ( (*cptr++ & 0xc0) != 0x80 ) {
6915 xmlGenericError(xmlGenericErrorContext,
6916 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6917 break;
6918 }
6919 if (ch & 0x80) /* must have had error encountered */
6920 break;
6921 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006922 }
Owen Taylor3473f882001-02-23 17:55:21 +00006923 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006924 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6925 xmlBufferFree(target);
6926 xmlXPathFreeObject(str);
6927 xmlXPathFreeObject(from);
6928 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006929}
6930
6931/**
6932 * xmlXPathBooleanFunction:
6933 * @ctxt: the XPath Parser context
6934 * @nargs: the number of arguments
6935 *
6936 * Implement the boolean() XPath function
6937 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00006938 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006939 * - a number is true if and only if it is neither positive or
6940 * negative zero nor NaN
6941 * - a node-set is true if and only if it is non-empty
6942 * - a string is true if and only if its length is non-zero
6943 */
6944void
6945xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6946 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006947
6948 CHECK_ARITY(1);
6949 cur = valuePop(ctxt);
6950 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006951 cur = xmlXPathConvertBoolean(cur);
6952 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006953}
6954
6955/**
6956 * xmlXPathNotFunction:
6957 * @ctxt: the XPath Parser context
6958 * @nargs: the number of arguments
6959 *
6960 * Implement the not() XPath function
6961 * boolean not(boolean)
6962 * The not function returns true if its argument is false,
6963 * and false otherwise.
6964 */
6965void
6966xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6967 CHECK_ARITY(1);
6968 CAST_TO_BOOLEAN;
6969 CHECK_TYPE(XPATH_BOOLEAN);
6970 ctxt->value->boolval = ! ctxt->value->boolval;
6971}
6972
6973/**
6974 * xmlXPathTrueFunction:
6975 * @ctxt: the XPath Parser context
6976 * @nargs: the number of arguments
6977 *
6978 * Implement the true() XPath function
6979 * boolean true()
6980 */
6981void
6982xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6983 CHECK_ARITY(0);
6984 valuePush(ctxt, xmlXPathNewBoolean(1));
6985}
6986
6987/**
6988 * xmlXPathFalseFunction:
6989 * @ctxt: the XPath Parser context
6990 * @nargs: the number of arguments
6991 *
6992 * Implement the false() XPath function
6993 * boolean false()
6994 */
6995void
6996xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6997 CHECK_ARITY(0);
6998 valuePush(ctxt, xmlXPathNewBoolean(0));
6999}
7000
7001/**
7002 * xmlXPathLangFunction:
7003 * @ctxt: the XPath Parser context
7004 * @nargs: the number of arguments
7005 *
7006 * Implement the lang() XPath function
7007 * boolean lang(string)
7008 * The lang function returns true or false depending on whether the
7009 * language of the context node as specified by xml:lang attributes
7010 * is the same as or is a sublanguage of the language specified by
7011 * the argument string. The language of the context node is determined
7012 * by the value of the xml:lang attribute on the context node, or, if
7013 * the context node has no xml:lang attribute, by the value of the
7014 * xml:lang attribute on the nearest ancestor of the context node that
7015 * has an xml:lang attribute. If there is no such attribute, then lang
7016 * returns false. If there is such an attribute, then lang returns
7017 * true if the attribute value is equal to the argument ignoring case,
7018 * or if there is some suffix starting with - such that the attribute
7019 * value is equal to the argument ignoring that suffix of the attribute
7020 * value and ignoring case.
7021 */
7022void
7023xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7024 xmlXPathObjectPtr val;
7025 const xmlChar *theLang;
7026 const xmlChar *lang;
7027 int ret = 0;
7028 int i;
7029
7030 CHECK_ARITY(1);
7031 CAST_TO_STRING;
7032 CHECK_TYPE(XPATH_STRING);
7033 val = valuePop(ctxt);
7034 lang = val->stringval;
7035 theLang = xmlNodeGetLang(ctxt->context->node);
7036 if ((theLang != NULL) && (lang != NULL)) {
7037 for (i = 0;lang[i] != 0;i++)
7038 if (toupper(lang[i]) != toupper(theLang[i]))
7039 goto not_equal;
7040 ret = 1;
7041 }
7042not_equal:
William M. Bracka59ddb52004-02-25 08:12:32 +00007043 xmlFree((void *)theLang);
Owen Taylor3473f882001-02-23 17:55:21 +00007044 xmlXPathFreeObject(val);
7045 valuePush(ctxt, xmlXPathNewBoolean(ret));
7046}
7047
7048/**
7049 * xmlXPathNumberFunction:
7050 * @ctxt: the XPath Parser context
7051 * @nargs: the number of arguments
7052 *
7053 * Implement the number() XPath function
7054 * number number(object?)
7055 */
7056void
7057xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7058 xmlXPathObjectPtr cur;
7059 double res;
7060
7061 if (nargs == 0) {
7062 if (ctxt->context->node == NULL) {
7063 valuePush(ctxt, xmlXPathNewFloat(0.0));
7064 } else {
7065 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7066
7067 res = xmlXPathStringEvalNumber(content);
7068 valuePush(ctxt, xmlXPathNewFloat(res));
7069 xmlFree(content);
7070 }
7071 return;
7072 }
7073
7074 CHECK_ARITY(1);
7075 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007076 cur = xmlXPathConvertNumber(cur);
7077 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007078}
7079
7080/**
7081 * xmlXPathSumFunction:
7082 * @ctxt: the XPath Parser context
7083 * @nargs: the number of arguments
7084 *
7085 * Implement the sum() XPath function
7086 * number sum(node-set)
7087 * The sum function returns the sum of the values of the nodes in
7088 * the argument node-set.
7089 */
7090void
7091xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7092 xmlXPathObjectPtr cur;
7093 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007094 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007095
7096 CHECK_ARITY(1);
7097 if ((ctxt->value == NULL) ||
7098 ((ctxt->value->type != XPATH_NODESET) &&
7099 (ctxt->value->type != XPATH_XSLT_TREE)))
7100 XP_ERROR(XPATH_INVALID_TYPE);
7101 cur = valuePop(ctxt);
7102
William M. Brack08171912003-12-29 02:52:11 +00007103 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007104 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7105 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007106 }
7107 }
William M. Brack08171912003-12-29 02:52:11 +00007108 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007109 xmlXPathFreeObject(cur);
7110}
7111
7112/**
7113 * xmlXPathFloorFunction:
7114 * @ctxt: the XPath Parser context
7115 * @nargs: the number of arguments
7116 *
7117 * Implement the floor() XPath function
7118 * number floor(number)
7119 * The floor function returns the largest (closest to positive infinity)
7120 * number that is not greater than the argument and that is an integer.
7121 */
7122void
7123xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007124 double f;
7125
Owen Taylor3473f882001-02-23 17:55:21 +00007126 CHECK_ARITY(1);
7127 CAST_TO_NUMBER;
7128 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007129
7130 f = (double)((int) ctxt->value->floatval);
7131 if (f != ctxt->value->floatval) {
7132 if (ctxt->value->floatval > 0)
7133 ctxt->value->floatval = f;
7134 else
7135 ctxt->value->floatval = f - 1;
7136 }
Owen Taylor3473f882001-02-23 17:55:21 +00007137}
7138
7139/**
7140 * xmlXPathCeilingFunction:
7141 * @ctxt: the XPath Parser context
7142 * @nargs: the number of arguments
7143 *
7144 * Implement the ceiling() XPath function
7145 * number ceiling(number)
7146 * The ceiling function returns the smallest (closest to negative infinity)
7147 * number that is not less than the argument and that is an integer.
7148 */
7149void
7150xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7151 double f;
7152
7153 CHECK_ARITY(1);
7154 CAST_TO_NUMBER;
7155 CHECK_TYPE(XPATH_NUMBER);
7156
7157#if 0
7158 ctxt->value->floatval = ceil(ctxt->value->floatval);
7159#else
7160 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007161 if (f != ctxt->value->floatval) {
7162 if (ctxt->value->floatval > 0)
7163 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007164 else {
7165 if (ctxt->value->floatval < 0 && f == 0)
7166 ctxt->value->floatval = xmlXPathNZERO;
7167 else
7168 ctxt->value->floatval = f;
7169 }
7170
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007171 }
Owen Taylor3473f882001-02-23 17:55:21 +00007172#endif
7173}
7174
7175/**
7176 * xmlXPathRoundFunction:
7177 * @ctxt: the XPath Parser context
7178 * @nargs: the number of arguments
7179 *
7180 * Implement the round() XPath function
7181 * number round(number)
7182 * The round function returns the number that is closest to the
7183 * argument and that is an integer. If there are two such numbers,
7184 * then the one that is even is returned.
7185 */
7186void
7187xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7188 double f;
7189
7190 CHECK_ARITY(1);
7191 CAST_TO_NUMBER;
7192 CHECK_TYPE(XPATH_NUMBER);
7193
Daniel Veillardcda96922001-08-21 10:56:31 +00007194 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7195 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7196 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007197 (ctxt->value->floatval == 0.0))
7198 return;
7199
Owen Taylor3473f882001-02-23 17:55:21 +00007200 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007201 if (ctxt->value->floatval < 0) {
7202 if (ctxt->value->floatval < f - 0.5)
7203 ctxt->value->floatval = f - 1;
7204 else
7205 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007206 if (ctxt->value->floatval == 0)
7207 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007208 } else {
7209 if (ctxt->value->floatval < f + 0.5)
7210 ctxt->value->floatval = f;
7211 else
7212 ctxt->value->floatval = f + 1;
7213 }
Owen Taylor3473f882001-02-23 17:55:21 +00007214}
7215
7216/************************************************************************
7217 * *
7218 * The Parser *
7219 * *
7220 ************************************************************************/
7221
7222/*
William M. Brack08171912003-12-29 02:52:11 +00007223 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007224 * implementation.
7225 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007226static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007227static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007228static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007229static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007230static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7231 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007232
7233/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007234 * xmlXPathCurrentChar:
7235 * @ctxt: the XPath parser context
7236 * @cur: pointer to the beginning of the char
7237 * @len: pointer to the length of the char read
7238 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007239 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007240 * bytes in the input buffer.
7241 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007242 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007243 */
7244
7245static int
7246xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7247 unsigned char c;
7248 unsigned int val;
7249 const xmlChar *cur;
7250
7251 if (ctxt == NULL)
7252 return(0);
7253 cur = ctxt->cur;
7254
7255 /*
7256 * We are supposed to handle UTF8, check it's valid
7257 * From rfc2044: encoding of the Unicode values on UTF-8:
7258 *
7259 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7260 * 0000 0000-0000 007F 0xxxxxxx
7261 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7262 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7263 *
7264 * Check for the 0x110000 limit too
7265 */
7266 c = *cur;
7267 if (c & 0x80) {
7268 if ((cur[1] & 0xc0) != 0x80)
7269 goto encoding_error;
7270 if ((c & 0xe0) == 0xe0) {
7271
7272 if ((cur[2] & 0xc0) != 0x80)
7273 goto encoding_error;
7274 if ((c & 0xf0) == 0xf0) {
7275 if (((c & 0xf8) != 0xf0) ||
7276 ((cur[3] & 0xc0) != 0x80))
7277 goto encoding_error;
7278 /* 4-byte code */
7279 *len = 4;
7280 val = (cur[0] & 0x7) << 18;
7281 val |= (cur[1] & 0x3f) << 12;
7282 val |= (cur[2] & 0x3f) << 6;
7283 val |= cur[3] & 0x3f;
7284 } else {
7285 /* 3-byte code */
7286 *len = 3;
7287 val = (cur[0] & 0xf) << 12;
7288 val |= (cur[1] & 0x3f) << 6;
7289 val |= cur[2] & 0x3f;
7290 }
7291 } else {
7292 /* 2-byte code */
7293 *len = 2;
7294 val = (cur[0] & 0x1f) << 6;
7295 val |= cur[1] & 0x3f;
7296 }
7297 if (!IS_CHAR(val)) {
7298 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7299 }
7300 return(val);
7301 } else {
7302 /* 1-byte code */
7303 *len = 1;
7304 return((int) *cur);
7305 }
7306encoding_error:
7307 /*
William M. Brack08171912003-12-29 02:52:11 +00007308 * If we detect an UTF8 error that probably means that the
7309 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007310 * declaration header. Report the error and switch the encoding
7311 * to ISO-Latin-1 (if you don't like this policy, just declare the
7312 * encoding !)
7313 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007314 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007315 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007316}
7317
7318/**
Owen Taylor3473f882001-02-23 17:55:21 +00007319 * xmlXPathParseNCName:
7320 * @ctxt: the XPath Parser context
7321 *
7322 * parse an XML namespace non qualified name.
7323 *
7324 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7325 *
7326 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7327 * CombiningChar | Extender
7328 *
7329 * Returns the namespace name or NULL
7330 */
7331
7332xmlChar *
7333xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007334 const xmlChar *in;
7335 xmlChar *ret;
7336 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007337
Daniel Veillard2156a562001-04-28 12:24:34 +00007338 /*
7339 * Accelerator for simple ASCII names
7340 */
7341 in = ctxt->cur;
7342 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7343 ((*in >= 0x41) && (*in <= 0x5A)) ||
7344 (*in == '_')) {
7345 in++;
7346 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7347 ((*in >= 0x41) && (*in <= 0x5A)) ||
7348 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007349 (*in == '_') || (*in == '.') ||
7350 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007351 in++;
7352 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7353 (*in == '[') || (*in == ']') || (*in == ':') ||
7354 (*in == '@') || (*in == '*')) {
7355 count = in - ctxt->cur;
7356 if (count == 0)
7357 return(NULL);
7358 ret = xmlStrndup(ctxt->cur, count);
7359 ctxt->cur = in;
7360 return(ret);
7361 }
7362 }
7363 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007364}
7365
Daniel Veillard2156a562001-04-28 12:24:34 +00007366
Owen Taylor3473f882001-02-23 17:55:21 +00007367/**
7368 * xmlXPathParseQName:
7369 * @ctxt: the XPath Parser context
7370 * @prefix: a xmlChar **
7371 *
7372 * parse an XML qualified name
7373 *
7374 * [NS 5] QName ::= (Prefix ':')? LocalPart
7375 *
7376 * [NS 6] Prefix ::= NCName
7377 *
7378 * [NS 7] LocalPart ::= NCName
7379 *
7380 * Returns the function returns the local part, and prefix is updated
7381 * to get the Prefix if any.
7382 */
7383
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007384static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007385xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7386 xmlChar *ret = NULL;
7387
7388 *prefix = NULL;
7389 ret = xmlXPathParseNCName(ctxt);
7390 if (CUR == ':') {
7391 *prefix = ret;
7392 NEXT;
7393 ret = xmlXPathParseNCName(ctxt);
7394 }
7395 return(ret);
7396}
7397
7398/**
7399 * xmlXPathParseName:
7400 * @ctxt: the XPath Parser context
7401 *
7402 * parse an XML name
7403 *
7404 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7405 * CombiningChar | Extender
7406 *
7407 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7408 *
7409 * Returns the namespace name or NULL
7410 */
7411
7412xmlChar *
7413xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007414 const xmlChar *in;
7415 xmlChar *ret;
7416 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007417
Daniel Veillard61d80a22001-04-27 17:13:01 +00007418 /*
7419 * Accelerator for simple ASCII names
7420 */
7421 in = ctxt->cur;
7422 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7423 ((*in >= 0x41) && (*in <= 0x5A)) ||
7424 (*in == '_') || (*in == ':')) {
7425 in++;
7426 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7427 ((*in >= 0x41) && (*in <= 0x5A)) ||
7428 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007429 (*in == '_') || (*in == '-') ||
7430 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007431 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007432 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007433 count = in - ctxt->cur;
7434 ret = xmlStrndup(ctxt->cur, count);
7435 ctxt->cur = in;
7436 return(ret);
7437 }
7438 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007439 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007440}
7441
Daniel Veillard61d80a22001-04-27 17:13:01 +00007442static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007443xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007444 xmlChar buf[XML_MAX_NAMELEN + 5];
7445 int len = 0, l;
7446 int c;
7447
7448 /*
7449 * Handler for more complex cases
7450 */
7451 c = CUR_CHAR(l);
7452 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007453 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7454 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007455 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007456 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007457 return(NULL);
7458 }
7459
7460 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7461 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7462 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007463 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007464 (IS_COMBINING(c)) ||
7465 (IS_EXTENDER(c)))) {
7466 COPY_BUF(l,buf,len,c);
7467 NEXTL(l);
7468 c = CUR_CHAR(l);
7469 if (len >= XML_MAX_NAMELEN) {
7470 /*
7471 * Okay someone managed to make a huge name, so he's ready to pay
7472 * for the processing speed.
7473 */
7474 xmlChar *buffer;
7475 int max = len * 2;
7476
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007477 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007478 if (buffer == NULL) {
7479 XP_ERROR0(XPATH_MEMORY_ERROR);
7480 }
7481 memcpy(buffer, buf, len);
7482 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7483 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007484 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007485 (IS_COMBINING(c)) ||
7486 (IS_EXTENDER(c))) {
7487 if (len + 10 > max) {
7488 max *= 2;
7489 buffer = (xmlChar *) xmlRealloc(buffer,
7490 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007491 if (buffer == NULL) {
7492 XP_ERROR0(XPATH_MEMORY_ERROR);
7493 }
7494 }
7495 COPY_BUF(l,buffer,len,c);
7496 NEXTL(l);
7497 c = CUR_CHAR(l);
7498 }
7499 buffer[len] = 0;
7500 return(buffer);
7501 }
7502 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007503 if (len == 0)
7504 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007505 return(xmlStrndup(buf, len));
7506}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007507
7508#define MAX_FRAC 20
7509
William M. Brack372a4452004-02-17 13:09:23 +00007510/*
7511 * These are used as divisors for the fractional part of a number.
7512 * Since the table includes 1.0 (representing '0' fractional digits),
7513 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
7514 */
7515static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007516 1.0, 10.0, 100.0, 1000.0, 10000.0,
7517 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7518 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7519 100000000000000.0,
7520 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00007521 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00007522};
7523
Owen Taylor3473f882001-02-23 17:55:21 +00007524/**
7525 * xmlXPathStringEvalNumber:
7526 * @str: A string to scan
7527 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007528 * [30a] Float ::= Number ('e' Digits?)?
7529 *
Owen Taylor3473f882001-02-23 17:55:21 +00007530 * [30] Number ::= Digits ('.' Digits?)?
7531 * | '.' Digits
7532 * [31] Digits ::= [0-9]+
7533 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007534 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007535 * In complement of the Number expression, this function also handles
7536 * negative values : '-' Number.
7537 *
7538 * Returns the double value.
7539 */
7540double
7541xmlXPathStringEvalNumber(const xmlChar *str) {
7542 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007543 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007544 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007545 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007546 int exponent = 0;
7547 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007548#ifdef __GNUC__
7549 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007550 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007551#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007552 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007553 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007554 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7555 return(xmlXPathNAN);
7556 }
7557 if (*cur == '-') {
7558 isneg = 1;
7559 cur++;
7560 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007561
7562#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007563 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007564 * tmp/temp is a workaround against a gcc compiler bug
7565 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007566 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007567 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007568 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007569 ret = ret * 10;
7570 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007571 ok = 1;
7572 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007573 temp = (double) tmp;
7574 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007575 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007576#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007577 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007578 while ((*cur >= '0') && (*cur <= '9')) {
7579 ret = ret * 10 + (*cur - '0');
7580 ok = 1;
7581 cur++;
7582 }
7583#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007584
Owen Taylor3473f882001-02-23 17:55:21 +00007585 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007586 int v, frac = 0;
7587 double fraction = 0;
7588
Owen Taylor3473f882001-02-23 17:55:21 +00007589 cur++;
7590 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7591 return(xmlXPathNAN);
7592 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007593 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7594 v = (*cur - '0');
7595 fraction = fraction * 10 + v;
7596 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007597 cur++;
7598 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007599 fraction /= my_pow10[frac];
7600 ret = ret + fraction;
7601 while ((*cur >= '0') && (*cur <= '9'))
7602 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007603 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007604 if ((*cur == 'e') || (*cur == 'E')) {
7605 cur++;
7606 if (*cur == '-') {
7607 is_exponent_negative = 1;
7608 cur++;
William M. Brack99127052004-05-24 02:52:28 +00007609 } else if (*cur == '+') {
7610 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007611 }
7612 while ((*cur >= '0') && (*cur <= '9')) {
7613 exponent = exponent * 10 + (*cur - '0');
7614 cur++;
7615 }
7616 }
William M. Brack76e95df2003-10-18 16:20:14 +00007617 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007618 if (*cur != 0) return(xmlXPathNAN);
7619 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007620 if (is_exponent_negative) exponent = -exponent;
7621 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007622 return(ret);
7623}
7624
7625/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007626 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007627 * @ctxt: the XPath Parser context
7628 *
7629 * [30] Number ::= Digits ('.' Digits?)?
7630 * | '.' Digits
7631 * [31] Digits ::= [0-9]+
7632 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007633 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007634 *
7635 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007636static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007637xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7638{
Owen Taylor3473f882001-02-23 17:55:21 +00007639 double ret = 0.0;
7640 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007641 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007642 int exponent = 0;
7643 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007644#ifdef __GNUC__
7645 unsigned long tmp = 0;
7646 double temp;
7647#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007648
7649 CHECK_ERROR;
7650 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7651 XP_ERROR(XPATH_NUMBER_ERROR);
7652 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007653#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007654 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007655 * tmp/temp is a workaround against a gcc compiler bug
7656 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007657 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007658 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007659 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007660 ret = ret * 10;
7661 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007662 ok = 1;
7663 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007664 temp = (double) tmp;
7665 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007666 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007667#else
7668 ret = 0;
7669 while ((CUR >= '0') && (CUR <= '9')) {
7670 ret = ret * 10 + (CUR - '0');
7671 ok = 1;
7672 NEXT;
7673 }
7674#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007675 if (CUR == '.') {
7676 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007677 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7678 XP_ERROR(XPATH_NUMBER_ERROR);
7679 }
7680 while ((CUR >= '0') && (CUR <= '9')) {
7681 mult /= 10;
7682 ret = ret + (CUR - '0') * mult;
7683 NEXT;
7684 }
Owen Taylor3473f882001-02-23 17:55:21 +00007685 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007686 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007687 NEXT;
7688 if (CUR == '-') {
7689 is_exponent_negative = 1;
7690 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00007691 } else if (CUR == '+') {
7692 NEXT;
7693 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007694 while ((CUR >= '0') && (CUR <= '9')) {
7695 exponent = exponent * 10 + (CUR - '0');
7696 NEXT;
7697 }
7698 if (is_exponent_negative)
7699 exponent = -exponent;
7700 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007701 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007702 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007703 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007704}
7705
7706/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007707 * xmlXPathParseLiteral:
7708 * @ctxt: the XPath Parser context
7709 *
7710 * Parse a Literal
7711 *
7712 * [29] Literal ::= '"' [^"]* '"'
7713 * | "'" [^']* "'"
7714 *
7715 * Returns the value found or NULL in case of error
7716 */
7717static xmlChar *
7718xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7719 const xmlChar *q;
7720 xmlChar *ret = NULL;
7721
7722 if (CUR == '"') {
7723 NEXT;
7724 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007725 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007726 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007727 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007728 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7729 } else {
7730 ret = xmlStrndup(q, CUR_PTR - q);
7731 NEXT;
7732 }
7733 } else if (CUR == '\'') {
7734 NEXT;
7735 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007736 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007737 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007738 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007739 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7740 } else {
7741 ret = xmlStrndup(q, CUR_PTR - q);
7742 NEXT;
7743 }
7744 } else {
7745 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7746 }
7747 return(ret);
7748}
7749
7750/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007751 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007752 * @ctxt: the XPath Parser context
7753 *
7754 * Parse a Literal and push it on the stack.
7755 *
7756 * [29] Literal ::= '"' [^"]* '"'
7757 * | "'" [^']* "'"
7758 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007759 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007760 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007761static void
7762xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007763 const xmlChar *q;
7764 xmlChar *ret = NULL;
7765
7766 if (CUR == '"') {
7767 NEXT;
7768 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007769 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007770 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007771 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007772 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7773 } else {
7774 ret = xmlStrndup(q, CUR_PTR - q);
7775 NEXT;
7776 }
7777 } else if (CUR == '\'') {
7778 NEXT;
7779 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007780 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007781 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007782 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007783 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7784 } else {
7785 ret = xmlStrndup(q, CUR_PTR - q);
7786 NEXT;
7787 }
7788 } else {
7789 XP_ERROR(XPATH_START_LITERAL_ERROR);
7790 }
7791 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007792 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7793 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007794 xmlFree(ret);
7795}
7796
7797/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007798 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007799 * @ctxt: the XPath Parser context
7800 *
7801 * Parse a VariableReference, evaluate it and push it on the stack.
7802 *
7803 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00007804 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00007805 * of any of the types that are possible for the value of an expression,
7806 * and may also be of additional types not specified here.
7807 *
7808 * Early evaluation is possible since:
7809 * The variable bindings [...] used to evaluate a subexpression are
7810 * always the same as those used to evaluate the containing expression.
7811 *
7812 * [36] VariableReference ::= '$' QName
7813 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007814static void
7815xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007816 xmlChar *name;
7817 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007818
7819 SKIP_BLANKS;
7820 if (CUR != '$') {
7821 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7822 }
7823 NEXT;
7824 name = xmlXPathParseQName(ctxt, &prefix);
7825 if (name == NULL) {
7826 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7827 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007828 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007829 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7830 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007831 SKIP_BLANKS;
7832}
7833
7834/**
7835 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007836 * @name: a name string
7837 *
7838 * Is the name given a NodeType one.
7839 *
7840 * [38] NodeType ::= 'comment'
7841 * | 'text'
7842 * | 'processing-instruction'
7843 * | 'node'
7844 *
7845 * Returns 1 if true 0 otherwise
7846 */
7847int
7848xmlXPathIsNodeType(const xmlChar *name) {
7849 if (name == NULL)
7850 return(0);
7851
Daniel Veillard1971ee22002-01-31 20:29:19 +00007852 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007853 return(1);
7854 if (xmlStrEqual(name, BAD_CAST "text"))
7855 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007856 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007857 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007858 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007859 return(1);
7860 return(0);
7861}
7862
7863/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007864 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007865 * @ctxt: the XPath Parser context
7866 *
7867 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7868 * [17] Argument ::= Expr
7869 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007870 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007871 * pushed on the stack
7872 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007873static void
7874xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007875 xmlChar *name;
7876 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007877 int nbargs = 0;
7878
7879 name = xmlXPathParseQName(ctxt, &prefix);
7880 if (name == NULL) {
7881 XP_ERROR(XPATH_EXPR_ERROR);
7882 }
7883 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007884#ifdef DEBUG_EXPR
7885 if (prefix == NULL)
7886 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7887 name);
7888 else
7889 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7890 prefix, name);
7891#endif
7892
Owen Taylor3473f882001-02-23 17:55:21 +00007893 if (CUR != '(') {
7894 XP_ERROR(XPATH_EXPR_ERROR);
7895 }
7896 NEXT;
7897 SKIP_BLANKS;
7898
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007899 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007900 if (CUR != ')') {
7901 while (CUR != 0) {
7902 int op1 = ctxt->comp->last;
7903 ctxt->comp->last = -1;
7904 xmlXPathCompileExpr(ctxt);
7905 CHECK_ERROR;
7906 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7907 nbargs++;
7908 if (CUR == ')') break;
7909 if (CUR != ',') {
7910 XP_ERROR(XPATH_EXPR_ERROR);
7911 }
7912 NEXT;
7913 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007914 }
Owen Taylor3473f882001-02-23 17:55:21 +00007915 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007916 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7917 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007918 NEXT;
7919 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007920}
7921
7922/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007923 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007924 * @ctxt: the XPath Parser context
7925 *
7926 * [15] PrimaryExpr ::= VariableReference
7927 * | '(' Expr ')'
7928 * | Literal
7929 * | Number
7930 * | FunctionCall
7931 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007932 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007933 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007934static void
7935xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007936 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007937 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007938 else if (CUR == '(') {
7939 NEXT;
7940 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007941 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007942 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007943 if (CUR != ')') {
7944 XP_ERROR(XPATH_EXPR_ERROR);
7945 }
7946 NEXT;
7947 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00007948 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007949 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007950 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007951 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007952 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007953 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007954 }
7955 SKIP_BLANKS;
7956}
7957
7958/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007959 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007960 * @ctxt: the XPath Parser context
7961 *
7962 * [20] FilterExpr ::= PrimaryExpr
7963 * | FilterExpr Predicate
7964 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007965 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007966 * Square brackets are used to filter expressions in the same way that
7967 * they are used in location paths. It is an error if the expression to
7968 * be filtered does not evaluate to a node-set. The context node list
7969 * used for evaluating the expression in square brackets is the node-set
7970 * to be filtered listed in document order.
7971 */
7972
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007973static void
7974xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7975 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007976 CHECK_ERROR;
7977 SKIP_BLANKS;
7978
7979 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007980 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007981 SKIP_BLANKS;
7982 }
7983
7984
7985}
7986
7987/**
7988 * xmlXPathScanName:
7989 * @ctxt: the XPath Parser context
7990 *
7991 * Trickery: parse an XML name but without consuming the input flow
7992 * Needed to avoid insanity in the parser state.
7993 *
7994 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7995 * CombiningChar | Extender
7996 *
7997 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7998 *
7999 * [6] Names ::= Name (S Name)*
8000 *
8001 * Returns the Name parsed or NULL
8002 */
8003
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008004static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00008005xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +00008006 int len = 0, l;
8007 int c;
Daniel Veillard03226812004-11-01 14:55:21 +00008008 const xmlChar *cur;
8009 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00008010
Daniel Veillard03226812004-11-01 14:55:21 +00008011 cur = ctxt->cur;
8012
8013 c = CUR_CHAR(l);
8014 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8015 (!IS_LETTER(c) && (c != '_') &&
8016 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008017 return(NULL);
8018 }
8019
Daniel Veillard03226812004-11-01 14:55:21 +00008020 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8021 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8022 (c == '.') || (c == '-') ||
8023 (c == '_') || (c == ':') ||
8024 (IS_COMBINING(c)) ||
8025 (IS_EXTENDER(c)))) {
8026 len += l;
8027 NEXTL(l);
8028 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +00008029 }
Daniel Veillard03226812004-11-01 14:55:21 +00008030 ret = xmlStrndup(cur, ctxt->cur - cur);
8031 ctxt->cur = cur;
8032 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00008033}
8034
8035/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008036 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008037 * @ctxt: the XPath Parser context
8038 *
8039 * [19] PathExpr ::= LocationPath
8040 * | FilterExpr
8041 * | FilterExpr '/' RelativeLocationPath
8042 * | FilterExpr '//' RelativeLocationPath
8043 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008044 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008045 * The / operator and // operators combine an arbitrary expression
8046 * and a relative location path. It is an error if the expression
8047 * does not evaluate to a node-set.
8048 * The / operator does composition in the same way as when / is
8049 * used in a location path. As in location paths, // is short for
8050 * /descendant-or-self::node()/.
8051 */
8052
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008053static void
8054xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008055 int lc = 1; /* Should we branch to LocationPath ? */
8056 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8057
8058 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008059 if ((CUR == '$') || (CUR == '(') ||
8060 (IS_ASCII_DIGIT(CUR)) ||
8061 (CUR == '\'') || (CUR == '"') ||
8062 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008063 lc = 0;
8064 } else if (CUR == '*') {
8065 /* relative or absolute location path */
8066 lc = 1;
8067 } else if (CUR == '/') {
8068 /* relative or absolute location path */
8069 lc = 1;
8070 } else if (CUR == '@') {
8071 /* relative abbreviated attribute location path */
8072 lc = 1;
8073 } else if (CUR == '.') {
8074 /* relative abbreviated attribute location path */
8075 lc = 1;
8076 } else {
8077 /*
8078 * Problem is finding if we have a name here whether it's:
8079 * - a nodetype
8080 * - a function call in which case it's followed by '('
8081 * - an axis in which case it's followed by ':'
8082 * - a element name
8083 * We do an a priori analysis here rather than having to
8084 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008085 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008086 * read/write/debug.
8087 */
8088 SKIP_BLANKS;
8089 name = xmlXPathScanName(ctxt);
8090 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8091#ifdef DEBUG_STEP
8092 xmlGenericError(xmlGenericErrorContext,
8093 "PathExpr: Axis\n");
8094#endif
8095 lc = 1;
8096 xmlFree(name);
8097 } else if (name != NULL) {
8098 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008099
8100
8101 while (NXT(len) != 0) {
8102 if (NXT(len) == '/') {
8103 /* element name */
8104#ifdef DEBUG_STEP
8105 xmlGenericError(xmlGenericErrorContext,
8106 "PathExpr: AbbrRelLocation\n");
8107#endif
8108 lc = 1;
8109 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008110 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008111 /* ignore blanks */
8112 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008113 } else if (NXT(len) == ':') {
8114#ifdef DEBUG_STEP
8115 xmlGenericError(xmlGenericErrorContext,
8116 "PathExpr: AbbrRelLocation\n");
8117#endif
8118 lc = 1;
8119 break;
8120 } else if ((NXT(len) == '(')) {
8121 /* Note Type or Function */
8122 if (xmlXPathIsNodeType(name)) {
8123#ifdef DEBUG_STEP
8124 xmlGenericError(xmlGenericErrorContext,
8125 "PathExpr: Type search\n");
8126#endif
8127 lc = 1;
8128 } else {
8129#ifdef DEBUG_STEP
8130 xmlGenericError(xmlGenericErrorContext,
8131 "PathExpr: function call\n");
8132#endif
8133 lc = 0;
8134 }
8135 break;
8136 } else if ((NXT(len) == '[')) {
8137 /* element name */
8138#ifdef DEBUG_STEP
8139 xmlGenericError(xmlGenericErrorContext,
8140 "PathExpr: AbbrRelLocation\n");
8141#endif
8142 lc = 1;
8143 break;
8144 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8145 (NXT(len) == '=')) {
8146 lc = 1;
8147 break;
8148 } else {
8149 lc = 1;
8150 break;
8151 }
8152 len++;
8153 }
8154 if (NXT(len) == 0) {
8155#ifdef DEBUG_STEP
8156 xmlGenericError(xmlGenericErrorContext,
8157 "PathExpr: AbbrRelLocation\n");
8158#endif
8159 /* element name */
8160 lc = 1;
8161 }
8162 xmlFree(name);
8163 } else {
William M. Brack08171912003-12-29 02:52:11 +00008164 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008165 XP_ERROR(XPATH_EXPR_ERROR);
8166 }
8167 }
8168
8169 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008170 if (CUR == '/') {
8171 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8172 } else {
8173 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008174 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008175 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008176 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008177 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008178 CHECK_ERROR;
8179 if ((CUR == '/') && (NXT(1) == '/')) {
8180 SKIP(2);
8181 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008182
8183 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8184 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8185 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8186
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008187 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008188 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008189 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008190 }
8191 }
8192 SKIP_BLANKS;
8193}
8194
8195/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008196 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008197 * @ctxt: the XPath Parser context
8198 *
8199 * [18] UnionExpr ::= PathExpr
8200 * | UnionExpr '|' PathExpr
8201 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008202 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008203 */
8204
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008205static void
8206xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8207 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008208 CHECK_ERROR;
8209 SKIP_BLANKS;
8210 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008211 int op1 = ctxt->comp->last;
8212 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008213
8214 NEXT;
8215 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008216 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008217
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008218 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8219
Owen Taylor3473f882001-02-23 17:55:21 +00008220 SKIP_BLANKS;
8221 }
Owen Taylor3473f882001-02-23 17:55:21 +00008222}
8223
8224/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008225 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008226 * @ctxt: the XPath Parser context
8227 *
8228 * [27] UnaryExpr ::= UnionExpr
8229 * | '-' UnaryExpr
8230 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008231 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008232 */
8233
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008234static void
8235xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008236 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008237 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008238
8239 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008240 while (CUR == '-') {
8241 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008242 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008243 NEXT;
8244 SKIP_BLANKS;
8245 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008246
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008247 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008248 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008249 if (found) {
8250 if (minus)
8251 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8252 else
8253 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008254 }
8255}
8256
8257/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008258 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008259 * @ctxt: the XPath Parser context
8260 *
8261 * [26] MultiplicativeExpr ::= UnaryExpr
8262 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8263 * | MultiplicativeExpr 'div' UnaryExpr
8264 * | MultiplicativeExpr 'mod' UnaryExpr
8265 * [34] MultiplyOperator ::= '*'
8266 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008267 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008268 */
8269
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008270static void
8271xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8272 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008273 CHECK_ERROR;
8274 SKIP_BLANKS;
8275 while ((CUR == '*') ||
8276 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8277 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8278 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008279 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008280
8281 if (CUR == '*') {
8282 op = 0;
8283 NEXT;
8284 } else if (CUR == 'd') {
8285 op = 1;
8286 SKIP(3);
8287 } else if (CUR == 'm') {
8288 op = 2;
8289 SKIP(3);
8290 }
8291 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008292 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008293 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008294 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008295 SKIP_BLANKS;
8296 }
8297}
8298
8299/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008300 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008301 * @ctxt: the XPath Parser context
8302 *
8303 * [25] AdditiveExpr ::= MultiplicativeExpr
8304 * | AdditiveExpr '+' MultiplicativeExpr
8305 * | AdditiveExpr '-' MultiplicativeExpr
8306 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008307 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008308 */
8309
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008310static void
8311xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008312
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008313 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008314 CHECK_ERROR;
8315 SKIP_BLANKS;
8316 while ((CUR == '+') || (CUR == '-')) {
8317 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008318 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008319
8320 if (CUR == '+') plus = 1;
8321 else plus = 0;
8322 NEXT;
8323 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008324 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008325 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008326 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008327 SKIP_BLANKS;
8328 }
8329}
8330
8331/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008332 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008333 * @ctxt: the XPath Parser context
8334 *
8335 * [24] RelationalExpr ::= AdditiveExpr
8336 * | RelationalExpr '<' AdditiveExpr
8337 * | RelationalExpr '>' AdditiveExpr
8338 * | RelationalExpr '<=' AdditiveExpr
8339 * | RelationalExpr '>=' AdditiveExpr
8340 *
8341 * A <= B > C is allowed ? Answer from James, yes with
8342 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8343 * which is basically what got implemented.
8344 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008345 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008346 * on the stack
8347 */
8348
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008349static void
8350xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8351 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008352 CHECK_ERROR;
8353 SKIP_BLANKS;
8354 while ((CUR == '<') ||
8355 (CUR == '>') ||
8356 ((CUR == '<') && (NXT(1) == '=')) ||
8357 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008358 int inf, strict;
8359 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008360
8361 if (CUR == '<') inf = 1;
8362 else inf = 0;
8363 if (NXT(1) == '=') strict = 0;
8364 else strict = 1;
8365 NEXT;
8366 if (!strict) NEXT;
8367 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008368 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008369 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008370 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008371 SKIP_BLANKS;
8372 }
8373}
8374
8375/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008376 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008377 * @ctxt: the XPath Parser context
8378 *
8379 * [23] EqualityExpr ::= RelationalExpr
8380 * | EqualityExpr '=' RelationalExpr
8381 * | EqualityExpr '!=' RelationalExpr
8382 *
8383 * A != B != C is allowed ? Answer from James, yes with
8384 * (RelationalExpr = RelationalExpr) = RelationalExpr
8385 * (RelationalExpr != RelationalExpr) != RelationalExpr
8386 * which is basically what got implemented.
8387 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008388 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008389 *
8390 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008391static void
8392xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8393 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008394 CHECK_ERROR;
8395 SKIP_BLANKS;
8396 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008397 int eq;
8398 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008399
8400 if (CUR == '=') eq = 1;
8401 else eq = 0;
8402 NEXT;
8403 if (!eq) NEXT;
8404 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008405 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008406 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008407 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008408 SKIP_BLANKS;
8409 }
8410}
8411
8412/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008413 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008414 * @ctxt: the XPath Parser context
8415 *
8416 * [22] AndExpr ::= EqualityExpr
8417 * | AndExpr 'and' EqualityExpr
8418 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008419 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008420 *
8421 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008422static void
8423xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8424 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008425 CHECK_ERROR;
8426 SKIP_BLANKS;
8427 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008428 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008429 SKIP(3);
8430 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008431 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008432 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008433 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008434 SKIP_BLANKS;
8435 }
8436}
8437
8438/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008439 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008440 * @ctxt: the XPath Parser context
8441 *
8442 * [14] Expr ::= OrExpr
8443 * [21] OrExpr ::= AndExpr
8444 * | OrExpr 'or' AndExpr
8445 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008446 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008447 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008448static void
8449xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8450 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008451 CHECK_ERROR;
8452 SKIP_BLANKS;
8453 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008454 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008455 SKIP(2);
8456 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008457 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008458 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008459 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8460 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008461 SKIP_BLANKS;
8462 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008463 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8464 /* more ops could be optimized too */
8465 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8466 }
Owen Taylor3473f882001-02-23 17:55:21 +00008467}
8468
8469/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008470 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008471 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008472 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008473 *
8474 * [8] Predicate ::= '[' PredicateExpr ']'
8475 * [9] PredicateExpr ::= Expr
8476 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008477 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008478 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008479static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008480xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008481 int op1 = ctxt->comp->last;
8482
8483 SKIP_BLANKS;
8484 if (CUR != '[') {
8485 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8486 }
8487 NEXT;
8488 SKIP_BLANKS;
8489
8490 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008491 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008492 CHECK_ERROR;
8493
8494 if (CUR != ']') {
8495 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8496 }
8497
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008498 if (filter)
8499 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8500 else
8501 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008502
8503 NEXT;
8504 SKIP_BLANKS;
8505}
8506
8507/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008508 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008509 * @ctxt: the XPath Parser context
8510 * @test: pointer to a xmlXPathTestVal
8511 * @type: pointer to a xmlXPathTypeVal
8512 * @prefix: placeholder for a possible name prefix
8513 *
8514 * [7] NodeTest ::= NameTest
8515 * | NodeType '(' ')'
8516 * | 'processing-instruction' '(' Literal ')'
8517 *
8518 * [37] NameTest ::= '*'
8519 * | NCName ':' '*'
8520 * | QName
8521 * [38] NodeType ::= 'comment'
8522 * | 'text'
8523 * | 'processing-instruction'
8524 * | 'node'
8525 *
William M. Brack08171912003-12-29 02:52:11 +00008526 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00008527 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008528static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008529xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8530 xmlXPathTypeVal *type, const xmlChar **prefix,
8531 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008532 int blanks;
8533
8534 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8535 STRANGE;
8536 return(NULL);
8537 }
William M. Brack78637da2003-07-31 14:47:38 +00008538 *type = (xmlXPathTypeVal) 0;
8539 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008540 *prefix = NULL;
8541 SKIP_BLANKS;
8542
8543 if ((name == NULL) && (CUR == '*')) {
8544 /*
8545 * All elements
8546 */
8547 NEXT;
8548 *test = NODE_TEST_ALL;
8549 return(NULL);
8550 }
8551
8552 if (name == NULL)
8553 name = xmlXPathParseNCName(ctxt);
8554 if (name == NULL) {
8555 XP_ERROR0(XPATH_EXPR_ERROR);
8556 }
8557
William M. Brack76e95df2003-10-18 16:20:14 +00008558 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008559 SKIP_BLANKS;
8560 if (CUR == '(') {
8561 NEXT;
8562 /*
8563 * NodeType or PI search
8564 */
8565 if (xmlStrEqual(name, BAD_CAST "comment"))
8566 *type = NODE_TYPE_COMMENT;
8567 else if (xmlStrEqual(name, BAD_CAST "node"))
8568 *type = NODE_TYPE_NODE;
8569 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8570 *type = NODE_TYPE_PI;
8571 else if (xmlStrEqual(name, BAD_CAST "text"))
8572 *type = NODE_TYPE_TEXT;
8573 else {
8574 if (name != NULL)
8575 xmlFree(name);
8576 XP_ERROR0(XPATH_EXPR_ERROR);
8577 }
8578
8579 *test = NODE_TEST_TYPE;
8580
8581 SKIP_BLANKS;
8582 if (*type == NODE_TYPE_PI) {
8583 /*
8584 * Specific case: search a PI by name.
8585 */
Owen Taylor3473f882001-02-23 17:55:21 +00008586 if (name != NULL)
8587 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008588 name = NULL;
8589 if (CUR != ')') {
8590 name = xmlXPathParseLiteral(ctxt);
8591 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008592 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008593 SKIP_BLANKS;
8594 }
Owen Taylor3473f882001-02-23 17:55:21 +00008595 }
8596 if (CUR != ')') {
8597 if (name != NULL)
8598 xmlFree(name);
8599 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8600 }
8601 NEXT;
8602 return(name);
8603 }
8604 *test = NODE_TEST_NAME;
8605 if ((!blanks) && (CUR == ':')) {
8606 NEXT;
8607
8608 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008609 * Since currently the parser context don't have a
8610 * namespace list associated:
8611 * The namespace name for this prefix can be computed
8612 * only at evaluation time. The compilation is done
8613 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008614 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008615#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008616 *prefix = xmlXPathNsLookup(ctxt->context, name);
8617 if (name != NULL)
8618 xmlFree(name);
8619 if (*prefix == NULL) {
8620 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8621 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008622#else
8623 *prefix = name;
8624#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008625
8626 if (CUR == '*') {
8627 /*
8628 * All elements
8629 */
8630 NEXT;
8631 *test = NODE_TEST_ALL;
8632 return(NULL);
8633 }
8634
8635 name = xmlXPathParseNCName(ctxt);
8636 if (name == NULL) {
8637 XP_ERROR0(XPATH_EXPR_ERROR);
8638 }
8639 }
8640 return(name);
8641}
8642
8643/**
8644 * xmlXPathIsAxisName:
8645 * @name: a preparsed name token
8646 *
8647 * [6] AxisName ::= 'ancestor'
8648 * | 'ancestor-or-self'
8649 * | 'attribute'
8650 * | 'child'
8651 * | 'descendant'
8652 * | 'descendant-or-self'
8653 * | 'following'
8654 * | 'following-sibling'
8655 * | 'namespace'
8656 * | 'parent'
8657 * | 'preceding'
8658 * | 'preceding-sibling'
8659 * | 'self'
8660 *
8661 * Returns the axis or 0
8662 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008663static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008664xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008665 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008666 switch (name[0]) {
8667 case 'a':
8668 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8669 ret = AXIS_ANCESTOR;
8670 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8671 ret = AXIS_ANCESTOR_OR_SELF;
8672 if (xmlStrEqual(name, BAD_CAST "attribute"))
8673 ret = AXIS_ATTRIBUTE;
8674 break;
8675 case 'c':
8676 if (xmlStrEqual(name, BAD_CAST "child"))
8677 ret = AXIS_CHILD;
8678 break;
8679 case 'd':
8680 if (xmlStrEqual(name, BAD_CAST "descendant"))
8681 ret = AXIS_DESCENDANT;
8682 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8683 ret = AXIS_DESCENDANT_OR_SELF;
8684 break;
8685 case 'f':
8686 if (xmlStrEqual(name, BAD_CAST "following"))
8687 ret = AXIS_FOLLOWING;
8688 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8689 ret = AXIS_FOLLOWING_SIBLING;
8690 break;
8691 case 'n':
8692 if (xmlStrEqual(name, BAD_CAST "namespace"))
8693 ret = AXIS_NAMESPACE;
8694 break;
8695 case 'p':
8696 if (xmlStrEqual(name, BAD_CAST "parent"))
8697 ret = AXIS_PARENT;
8698 if (xmlStrEqual(name, BAD_CAST "preceding"))
8699 ret = AXIS_PRECEDING;
8700 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8701 ret = AXIS_PRECEDING_SIBLING;
8702 break;
8703 case 's':
8704 if (xmlStrEqual(name, BAD_CAST "self"))
8705 ret = AXIS_SELF;
8706 break;
8707 }
8708 return(ret);
8709}
8710
8711/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008712 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008713 * @ctxt: the XPath Parser context
8714 *
8715 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8716 * | AbbreviatedStep
8717 *
8718 * [12] AbbreviatedStep ::= '.' | '..'
8719 *
8720 * [5] AxisSpecifier ::= AxisName '::'
8721 * | AbbreviatedAxisSpecifier
8722 *
8723 * [13] AbbreviatedAxisSpecifier ::= '@'?
8724 *
8725 * Modified for XPtr range support as:
8726 *
8727 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8728 * | AbbreviatedStep
8729 * | 'range-to' '(' Expr ')' Predicate*
8730 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008731 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008732 * A location step of . is short for self::node(). This is
8733 * particularly useful in conjunction with //. For example, the
8734 * location path .//para is short for
8735 * self::node()/descendant-or-self::node()/child::para
8736 * and so will select all para descendant elements of the context
8737 * node.
8738 * Similarly, a location step of .. is short for parent::node().
8739 * For example, ../title is short for parent::node()/child::title
8740 * and so will select the title children of the parent of the context
8741 * node.
8742 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008743static void
8744xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008745#ifdef LIBXML_XPTR_ENABLED
8746 int rangeto = 0;
8747 int op2 = -1;
8748#endif
8749
Owen Taylor3473f882001-02-23 17:55:21 +00008750 SKIP_BLANKS;
8751 if ((CUR == '.') && (NXT(1) == '.')) {
8752 SKIP(2);
8753 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008754 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8755 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008756 } else if (CUR == '.') {
8757 NEXT;
8758 SKIP_BLANKS;
8759 } else {
8760 xmlChar *name = NULL;
8761 const xmlChar *prefix = NULL;
8762 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008763 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008764 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008765 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008766
8767 /*
8768 * The modification needed for XPointer change to the production
8769 */
8770#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008771 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008772 name = xmlXPathParseNCName(ctxt);
8773 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008774 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008775 xmlFree(name);
8776 SKIP_BLANKS;
8777 if (CUR != '(') {
8778 XP_ERROR(XPATH_EXPR_ERROR);
8779 }
8780 NEXT;
8781 SKIP_BLANKS;
8782
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008783 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008784 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008785 CHECK_ERROR;
8786
8787 SKIP_BLANKS;
8788 if (CUR != ')') {
8789 XP_ERROR(XPATH_EXPR_ERROR);
8790 }
8791 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008792 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008793 goto eval_predicates;
8794 }
8795 }
8796#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008797 if (CUR == '*') {
8798 axis = AXIS_CHILD;
8799 } else {
8800 if (name == NULL)
8801 name = xmlXPathParseNCName(ctxt);
8802 if (name != NULL) {
8803 axis = xmlXPathIsAxisName(name);
8804 if (axis != 0) {
8805 SKIP_BLANKS;
8806 if ((CUR == ':') && (NXT(1) == ':')) {
8807 SKIP(2);
8808 xmlFree(name);
8809 name = NULL;
8810 } else {
8811 /* an element name can conflict with an axis one :-\ */
8812 axis = AXIS_CHILD;
8813 }
Owen Taylor3473f882001-02-23 17:55:21 +00008814 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008815 axis = AXIS_CHILD;
8816 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008817 } else if (CUR == '@') {
8818 NEXT;
8819 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008820 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008821 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008822 }
Owen Taylor3473f882001-02-23 17:55:21 +00008823 }
8824
8825 CHECK_ERROR;
8826
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008827 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008828 if (test == 0)
8829 return;
8830
8831#ifdef DEBUG_STEP
8832 xmlGenericError(xmlGenericErrorContext,
8833 "Basis : computing new set\n");
8834#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008835
Owen Taylor3473f882001-02-23 17:55:21 +00008836#ifdef DEBUG_STEP
8837 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008838 if (ctxt->value == NULL)
8839 xmlGenericError(xmlGenericErrorContext, "no value\n");
8840 else if (ctxt->value->nodesetval == NULL)
8841 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8842 else
8843 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008844#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008845
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008846#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008847eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008848#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008849 op1 = ctxt->comp->last;
8850 ctxt->comp->last = -1;
8851
Owen Taylor3473f882001-02-23 17:55:21 +00008852 SKIP_BLANKS;
8853 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008854 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008855 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008856
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008857#ifdef LIBXML_XPTR_ENABLED
8858 if (rangeto) {
8859 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8860 } else
8861#endif
8862 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8863 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008864
Owen Taylor3473f882001-02-23 17:55:21 +00008865 }
8866#ifdef DEBUG_STEP
8867 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008868 if (ctxt->value == NULL)
8869 xmlGenericError(xmlGenericErrorContext, "no value\n");
8870 else if (ctxt->value->nodesetval == NULL)
8871 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8872 else
8873 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8874 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008875#endif
8876}
8877
8878/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008879 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008880 * @ctxt: the XPath Parser context
8881 *
8882 * [3] RelativeLocationPath ::= Step
8883 * | RelativeLocationPath '/' Step
8884 * | AbbreviatedRelativeLocationPath
8885 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8886 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008887 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008888 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008889static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008890xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008891(xmlXPathParserContextPtr ctxt) {
8892 SKIP_BLANKS;
8893 if ((CUR == '/') && (NXT(1) == '/')) {
8894 SKIP(2);
8895 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008896 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8897 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008898 } else if (CUR == '/') {
8899 NEXT;
8900 SKIP_BLANKS;
8901 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008902 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008903 SKIP_BLANKS;
8904 while (CUR == '/') {
8905 if ((CUR == '/') && (NXT(1) == '/')) {
8906 SKIP(2);
8907 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008908 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008909 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008910 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008911 } else if (CUR == '/') {
8912 NEXT;
8913 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008914 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008915 }
8916 SKIP_BLANKS;
8917 }
8918}
8919
8920/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008921 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008922 * @ctxt: the XPath Parser context
8923 *
8924 * [1] LocationPath ::= RelativeLocationPath
8925 * | AbsoluteLocationPath
8926 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8927 * | AbbreviatedAbsoluteLocationPath
8928 * [10] AbbreviatedAbsoluteLocationPath ::=
8929 * '//' RelativeLocationPath
8930 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008931 * Compile a location path
8932 *
Owen Taylor3473f882001-02-23 17:55:21 +00008933 * // is short for /descendant-or-self::node()/. For example,
8934 * //para is short for /descendant-or-self::node()/child::para and
8935 * so will select any para element in the document (even a para element
8936 * that is a document element will be selected by //para since the
8937 * document element node is a child of the root node); div//para is
8938 * short for div/descendant-or-self::node()/child::para and so will
8939 * select all para descendants of div children.
8940 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008941static void
8942xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008943 SKIP_BLANKS;
8944 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008945 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008946 } else {
8947 while (CUR == '/') {
8948 if ((CUR == '/') && (NXT(1) == '/')) {
8949 SKIP(2);
8950 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008951 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8952 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008953 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008954 } else if (CUR == '/') {
8955 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008956 SKIP_BLANKS;
8957 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +00008958 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00008959 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008960 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008961 }
8962 }
8963 }
8964}
8965
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008966/************************************************************************
8967 * *
8968 * XPath precompiled expression evaluation *
8969 * *
8970 ************************************************************************/
8971
Daniel Veillardf06307e2001-07-03 10:35:50 +00008972static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008973xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8974
8975/**
8976 * xmlXPathNodeCollectAndTest:
8977 * @ctxt: the XPath Parser context
8978 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008979 * @first: pointer to the first element in document order
8980 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008981 *
8982 * This is the function implementing a step: based on the current list
8983 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00008984 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008985 *
8986 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008987 *
William M. Brack08171912003-12-29 02:52:11 +00008988 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008989 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008990static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008991xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008992 xmlXPathStepOpPtr op,
8993 xmlNodePtr * first, xmlNodePtr * last)
8994{
William M. Brack78637da2003-07-31 14:47:38 +00008995 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
8996 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
8997 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008998 const xmlChar *prefix = op->value4;
8999 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009000 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009001
9002#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009003 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009004#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009005 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009006 xmlNodeSetPtr ret, list;
9007 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009008 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00009009 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009010 xmlNodePtr cur = NULL;
9011 xmlXPathObjectPtr obj;
9012 xmlNodeSetPtr nodelist;
9013 xmlNodePtr tmp;
9014
Daniel Veillardf06307e2001-07-03 10:35:50 +00009015 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009016 obj = valuePop(ctxt);
9017 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009018 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009019 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009020 URI = xmlXPathNsLookup(ctxt->context, prefix);
9021 if (URI == NULL)
9022 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00009023 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009024#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009025 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009026#endif
9027 switch (axis) {
9028 case AXIS_ANCESTOR:
9029#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009030 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009031#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009032 first = NULL;
9033 next = xmlXPathNextAncestor;
9034 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009035 case AXIS_ANCESTOR_OR_SELF:
9036#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009037 xmlGenericError(xmlGenericErrorContext,
9038 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009039#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009040 first = NULL;
9041 next = xmlXPathNextAncestorOrSelf;
9042 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009043 case AXIS_ATTRIBUTE:
9044#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009045 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009046#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009047 first = NULL;
9048 last = NULL;
9049 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009050 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009051 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009052 case AXIS_CHILD:
9053#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009054 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009055#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009056 last = NULL;
9057 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009058 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009059 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009060 case AXIS_DESCENDANT:
9061#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009062 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009063#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009064 last = NULL;
9065 next = xmlXPathNextDescendant;
9066 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009067 case AXIS_DESCENDANT_OR_SELF:
9068#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009069 xmlGenericError(xmlGenericErrorContext,
9070 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009071#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009072 last = NULL;
9073 next = xmlXPathNextDescendantOrSelf;
9074 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009075 case AXIS_FOLLOWING:
9076#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009077 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009078#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009079 last = NULL;
9080 next = xmlXPathNextFollowing;
9081 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009082 case AXIS_FOLLOWING_SIBLING:
9083#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009084 xmlGenericError(xmlGenericErrorContext,
9085 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009086#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009087 last = NULL;
9088 next = xmlXPathNextFollowingSibling;
9089 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009090 case AXIS_NAMESPACE:
9091#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009092 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009093#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009094 first = NULL;
9095 last = NULL;
9096 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009097 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009098 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009099 case AXIS_PARENT:
9100#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009101 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009102#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009103 first = NULL;
9104 next = xmlXPathNextParent;
9105 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009106 case AXIS_PRECEDING:
9107#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009108 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009109#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009110 first = NULL;
9111 next = xmlXPathNextPrecedingInternal;
9112 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009113 case AXIS_PRECEDING_SIBLING:
9114#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009115 xmlGenericError(xmlGenericErrorContext,
9116 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009117#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009118 first = NULL;
9119 next = xmlXPathNextPrecedingSibling;
9120 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009121 case AXIS_SELF:
9122#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009123 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009124#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009125 first = NULL;
9126 last = NULL;
9127 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009128 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009129 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009130 }
9131 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009132 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009133
9134 nodelist = obj->nodesetval;
9135 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009136 xmlXPathFreeObject(obj);
9137 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9138 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009139 }
9140 addNode = xmlXPathNodeSetAddUnique;
9141 ret = NULL;
9142#ifdef DEBUG_STEP
9143 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009144 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009145 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009146 case NODE_TEST_NONE:
9147 xmlGenericError(xmlGenericErrorContext,
9148 " searching for none !!!\n");
9149 break;
9150 case NODE_TEST_TYPE:
9151 xmlGenericError(xmlGenericErrorContext,
9152 " searching for type %d\n", type);
9153 break;
9154 case NODE_TEST_PI:
9155 xmlGenericError(xmlGenericErrorContext,
9156 " searching for PI !!!\n");
9157 break;
9158 case NODE_TEST_ALL:
9159 xmlGenericError(xmlGenericErrorContext,
9160 " searching for *\n");
9161 break;
9162 case NODE_TEST_NS:
9163 xmlGenericError(xmlGenericErrorContext,
9164 " searching for namespace %s\n",
9165 prefix);
9166 break;
9167 case NODE_TEST_NAME:
9168 xmlGenericError(xmlGenericErrorContext,
9169 " searching for name %s\n", name);
9170 if (prefix != NULL)
9171 xmlGenericError(xmlGenericErrorContext,
9172 " with namespace %s\n", prefix);
9173 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009174 }
9175 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9176#endif
9177 /*
9178 * 2.3 Node Tests
9179 * - For the attribute axis, the principal node type is attribute.
9180 * - For the namespace axis, the principal node type is namespace.
9181 * - For other axes, the principal node type is element.
9182 *
9183 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009184 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009185 * select all element children of the context node
9186 */
9187 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009188 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009189 ctxt->context->node = nodelist->nodeTab[i];
9190
Daniel Veillardf06307e2001-07-03 10:35:50 +00009191 cur = NULL;
9192 list = xmlXPathNodeSetCreate(NULL);
9193 do {
9194 cur = next(ctxt, cur);
9195 if (cur == NULL)
9196 break;
9197 if ((first != NULL) && (*first == cur))
9198 break;
9199 if (((t % 256) == 0) &&
9200 (first != NULL) && (*first != NULL) &&
9201 (xmlXPathCmpNodes(*first, cur) >= 0))
9202 break;
9203 if ((last != NULL) && (*last == cur))
9204 break;
9205 if (((t % 256) == 0) &&
9206 (last != NULL) && (*last != NULL) &&
9207 (xmlXPathCmpNodes(cur, *last) >= 0))
9208 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009209 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009210#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009211 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9212#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009213 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009214 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009215 ctxt->context->node = tmp;
9216 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009217 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009218 if ((cur->type == type) ||
9219 ((type == NODE_TYPE_NODE) &&
9220 ((cur->type == XML_DOCUMENT_NODE) ||
9221 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9222 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009223 (cur->type == XML_NAMESPACE_DECL) ||
9224 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009225 (cur->type == XML_PI_NODE) ||
9226 (cur->type == XML_COMMENT_NODE) ||
9227 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009228 (cur->type == XML_TEXT_NODE))) ||
9229 ((type == NODE_TYPE_TEXT) &&
9230 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009231#ifdef DEBUG_STEP
9232 n++;
9233#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009234 addNode(list, cur);
9235 }
9236 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009237 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009238 if (cur->type == XML_PI_NODE) {
9239 if ((name != NULL) &&
9240 (!xmlStrEqual(name, cur->name)))
9241 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009242#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009243 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009244#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009245 addNode(list, cur);
9246 }
9247 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009248 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009249 if (axis == AXIS_ATTRIBUTE) {
9250 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009251#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009252 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009253#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009254 addNode(list, cur);
9255 }
9256 } else if (axis == AXIS_NAMESPACE) {
9257 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009258#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009259 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009260#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009261 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9262 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009263 }
9264 } else {
9265 if (cur->type == XML_ELEMENT_NODE) {
9266 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009267#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009268 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009269#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009270 addNode(list, cur);
9271 } else if ((cur->ns != NULL) &&
9272 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009273#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009274 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009275#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009276 addNode(list, cur);
9277 }
9278 }
9279 }
9280 break;
9281 case NODE_TEST_NS:{
9282 TODO;
9283 break;
9284 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009285 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009286 switch (cur->type) {
9287 case XML_ELEMENT_NODE:
9288 if (xmlStrEqual(name, cur->name)) {
9289 if (prefix == NULL) {
9290 if (cur->ns == NULL) {
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 } else {
9297 if ((cur->ns != NULL) &&
9298 (xmlStrEqual(URI,
9299 cur->ns->href))) {
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 }
9306 }
9307 break;
9308 case XML_ATTRIBUTE_NODE:{
9309 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009310
Daniel Veillardf06307e2001-07-03 10:35:50 +00009311 if (xmlStrEqual(name, attr->name)) {
9312 if (prefix == NULL) {
9313 if ((attr->ns == NULL) ||
9314 (attr->ns->prefix == NULL)) {
9315#ifdef DEBUG_STEP
9316 n++;
9317#endif
9318 addNode(list,
9319 (xmlNodePtr) attr);
9320 }
9321 } else {
9322 if ((attr->ns != NULL) &&
9323 (xmlStrEqual(URI,
9324 attr->ns->
9325 href))) {
9326#ifdef DEBUG_STEP
9327 n++;
9328#endif
9329 addNode(list,
9330 (xmlNodePtr) attr);
9331 }
9332 }
9333 }
9334 break;
9335 }
9336 case XML_NAMESPACE_DECL:
9337 if (cur->type == XML_NAMESPACE_DECL) {
9338 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009339
Daniel Veillardf06307e2001-07-03 10:35:50 +00009340 if ((ns->prefix != NULL) && (name != NULL)
9341 && (xmlStrEqual(ns->prefix, name))) {
9342#ifdef DEBUG_STEP
9343 n++;
9344#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009345 xmlXPathNodeSetAddNs(list,
9346 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009347 }
9348 }
9349 break;
9350 default:
9351 break;
9352 }
9353 break;
9354 break;
9355 }
9356 } while (cur != NULL);
9357
9358 /*
9359 * If there is some predicate filtering do it now
9360 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009361 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009362 xmlXPathObjectPtr obj2;
9363
9364 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9365 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9366 CHECK_TYPE0(XPATH_NODESET);
9367 obj2 = valuePop(ctxt);
9368 list = obj2->nodesetval;
9369 obj2->nodesetval = NULL;
9370 xmlXPathFreeObject(obj2);
9371 }
9372 if (ret == NULL) {
9373 ret = list;
9374 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009375 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009376 xmlXPathFreeNodeSet(list);
9377 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009378 }
9379 ctxt->context->node = tmp;
9380#ifdef DEBUG_STEP
9381 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009382 "\nExamined %d nodes, found %d nodes at that step\n",
9383 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009384#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009385 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009386 if ((obj->boolval) && (obj->user != NULL)) {
9387 ctxt->value->boolval = 1;
9388 ctxt->value->user = obj->user;
9389 obj->user = NULL;
9390 obj->boolval = 0;
9391 }
9392 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009393 return(t);
9394}
9395
9396/**
9397 * xmlXPathNodeCollectAndTestNth:
9398 * @ctxt: the XPath Parser context
9399 * @op: the XPath precompiled step operation
9400 * @indx: the index to collect
9401 * @first: pointer to the first element in document order
9402 * @last: pointer to the last element in document order
9403 *
9404 * This is the function implementing a step: based on the current list
9405 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009406 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009407 *
9408 * Pushes the new NodeSet resulting from the search.
9409 * Returns the number of node traversed
9410 */
9411static int
9412xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9413 xmlXPathStepOpPtr op, int indx,
9414 xmlNodePtr * first, xmlNodePtr * last)
9415{
William M. Brack78637da2003-07-31 14:47:38 +00009416 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9417 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9418 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009419 const xmlChar *prefix = op->value4;
9420 const xmlChar *name = op->value5;
9421 const xmlChar *URI = NULL;
9422 int n = 0, t = 0;
9423
9424 int i;
9425 xmlNodeSetPtr list;
9426 xmlXPathTraversalFunction next = NULL;
9427 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9428 xmlNodePtr cur = NULL;
9429 xmlXPathObjectPtr obj;
9430 xmlNodeSetPtr nodelist;
9431 xmlNodePtr tmp;
9432
9433 CHECK_TYPE0(XPATH_NODESET);
9434 obj = valuePop(ctxt);
9435 addNode = xmlXPathNodeSetAdd;
9436 if (prefix != NULL) {
9437 URI = xmlXPathNsLookup(ctxt->context, prefix);
9438 if (URI == NULL)
9439 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9440 }
9441#ifdef DEBUG_STEP_NTH
9442 xmlGenericError(xmlGenericErrorContext, "new step : ");
9443 if (first != NULL) {
9444 if (*first != NULL)
9445 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9446 (*first)->name);
9447 else
9448 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9449 }
9450 if (last != NULL) {
9451 if (*last != NULL)
9452 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9453 (*last)->name);
9454 else
9455 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9456 }
9457#endif
9458 switch (axis) {
9459 case AXIS_ANCESTOR:
9460#ifdef DEBUG_STEP_NTH
9461 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9462#endif
9463 first = NULL;
9464 next = xmlXPathNextAncestor;
9465 break;
9466 case AXIS_ANCESTOR_OR_SELF:
9467#ifdef DEBUG_STEP_NTH
9468 xmlGenericError(xmlGenericErrorContext,
9469 "axis 'ancestors-or-self' ");
9470#endif
9471 first = NULL;
9472 next = xmlXPathNextAncestorOrSelf;
9473 break;
9474 case AXIS_ATTRIBUTE:
9475#ifdef DEBUG_STEP_NTH
9476 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9477#endif
9478 first = NULL;
9479 last = NULL;
9480 next = xmlXPathNextAttribute;
9481 break;
9482 case AXIS_CHILD:
9483#ifdef DEBUG_STEP_NTH
9484 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9485#endif
9486 last = NULL;
9487 next = xmlXPathNextChild;
9488 break;
9489 case AXIS_DESCENDANT:
9490#ifdef DEBUG_STEP_NTH
9491 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9492#endif
9493 last = NULL;
9494 next = xmlXPathNextDescendant;
9495 break;
9496 case AXIS_DESCENDANT_OR_SELF:
9497#ifdef DEBUG_STEP_NTH
9498 xmlGenericError(xmlGenericErrorContext,
9499 "axis 'descendant-or-self' ");
9500#endif
9501 last = NULL;
9502 next = xmlXPathNextDescendantOrSelf;
9503 break;
9504 case AXIS_FOLLOWING:
9505#ifdef DEBUG_STEP_NTH
9506 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9507#endif
9508 last = NULL;
9509 next = xmlXPathNextFollowing;
9510 break;
9511 case AXIS_FOLLOWING_SIBLING:
9512#ifdef DEBUG_STEP_NTH
9513 xmlGenericError(xmlGenericErrorContext,
9514 "axis 'following-siblings' ");
9515#endif
9516 last = NULL;
9517 next = xmlXPathNextFollowingSibling;
9518 break;
9519 case AXIS_NAMESPACE:
9520#ifdef DEBUG_STEP_NTH
9521 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9522#endif
9523 last = NULL;
9524 first = NULL;
9525 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9526 break;
9527 case AXIS_PARENT:
9528#ifdef DEBUG_STEP_NTH
9529 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9530#endif
9531 first = NULL;
9532 next = xmlXPathNextParent;
9533 break;
9534 case AXIS_PRECEDING:
9535#ifdef DEBUG_STEP_NTH
9536 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9537#endif
9538 first = NULL;
9539 next = xmlXPathNextPrecedingInternal;
9540 break;
9541 case AXIS_PRECEDING_SIBLING:
9542#ifdef DEBUG_STEP_NTH
9543 xmlGenericError(xmlGenericErrorContext,
9544 "axis 'preceding-sibling' ");
9545#endif
9546 first = NULL;
9547 next = xmlXPathNextPrecedingSibling;
9548 break;
9549 case AXIS_SELF:
9550#ifdef DEBUG_STEP_NTH
9551 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9552#endif
9553 first = NULL;
9554 last = NULL;
9555 next = xmlXPathNextSelf;
9556 break;
9557 }
9558 if (next == NULL)
9559 return(0);
9560
9561 nodelist = obj->nodesetval;
9562 if (nodelist == NULL) {
9563 xmlXPathFreeObject(obj);
9564 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9565 return(0);
9566 }
9567 addNode = xmlXPathNodeSetAddUnique;
9568#ifdef DEBUG_STEP_NTH
9569 xmlGenericError(xmlGenericErrorContext,
9570 " context contains %d nodes\n", nodelist->nodeNr);
9571 switch (test) {
9572 case NODE_TEST_NONE:
9573 xmlGenericError(xmlGenericErrorContext,
9574 " searching for none !!!\n");
9575 break;
9576 case NODE_TEST_TYPE:
9577 xmlGenericError(xmlGenericErrorContext,
9578 " searching for type %d\n", type);
9579 break;
9580 case NODE_TEST_PI:
9581 xmlGenericError(xmlGenericErrorContext,
9582 " searching for PI !!!\n");
9583 break;
9584 case NODE_TEST_ALL:
9585 xmlGenericError(xmlGenericErrorContext,
9586 " searching for *\n");
9587 break;
9588 case NODE_TEST_NS:
9589 xmlGenericError(xmlGenericErrorContext,
9590 " searching for namespace %s\n",
9591 prefix);
9592 break;
9593 case NODE_TEST_NAME:
9594 xmlGenericError(xmlGenericErrorContext,
9595 " searching for name %s\n", name);
9596 if (prefix != NULL)
9597 xmlGenericError(xmlGenericErrorContext,
9598 " with namespace %s\n", prefix);
9599 break;
9600 }
9601 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9602#endif
9603 /*
9604 * 2.3 Node Tests
9605 * - For the attribute axis, the principal node type is attribute.
9606 * - For the namespace axis, the principal node type is namespace.
9607 * - For other axes, the principal node type is element.
9608 *
9609 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009610 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009611 * select all element children of the context node
9612 */
9613 tmp = ctxt->context->node;
9614 list = xmlXPathNodeSetCreate(NULL);
9615 for (i = 0; i < nodelist->nodeNr; i++) {
9616 ctxt->context->node = nodelist->nodeTab[i];
9617
9618 cur = NULL;
9619 n = 0;
9620 do {
9621 cur = next(ctxt, cur);
9622 if (cur == NULL)
9623 break;
9624 if ((first != NULL) && (*first == cur))
9625 break;
9626 if (((t % 256) == 0) &&
9627 (first != NULL) && (*first != NULL) &&
9628 (xmlXPathCmpNodes(*first, cur) >= 0))
9629 break;
9630 if ((last != NULL) && (*last == cur))
9631 break;
9632 if (((t % 256) == 0) &&
9633 (last != NULL) && (*last != NULL) &&
9634 (xmlXPathCmpNodes(cur, *last) >= 0))
9635 break;
9636 t++;
9637 switch (test) {
9638 case NODE_TEST_NONE:
9639 ctxt->context->node = tmp;
9640 STRANGE return(0);
9641 case NODE_TEST_TYPE:
9642 if ((cur->type == type) ||
9643 ((type == NODE_TYPE_NODE) &&
9644 ((cur->type == XML_DOCUMENT_NODE) ||
9645 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9646 (cur->type == XML_ELEMENT_NODE) ||
9647 (cur->type == XML_PI_NODE) ||
9648 (cur->type == XML_COMMENT_NODE) ||
9649 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009650 (cur->type == XML_TEXT_NODE))) ||
9651 ((type == NODE_TYPE_TEXT) &&
9652 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009653 n++;
9654 if (n == indx)
9655 addNode(list, cur);
9656 }
9657 break;
9658 case NODE_TEST_PI:
9659 if (cur->type == XML_PI_NODE) {
9660 if ((name != NULL) &&
9661 (!xmlStrEqual(name, cur->name)))
9662 break;
9663 n++;
9664 if (n == indx)
9665 addNode(list, cur);
9666 }
9667 break;
9668 case NODE_TEST_ALL:
9669 if (axis == AXIS_ATTRIBUTE) {
9670 if (cur->type == XML_ATTRIBUTE_NODE) {
9671 n++;
9672 if (n == indx)
9673 addNode(list, cur);
9674 }
9675 } else if (axis == AXIS_NAMESPACE) {
9676 if (cur->type == XML_NAMESPACE_DECL) {
9677 n++;
9678 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009679 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9680 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009681 }
9682 } else {
9683 if (cur->type == XML_ELEMENT_NODE) {
9684 if (prefix == NULL) {
9685 n++;
9686 if (n == indx)
9687 addNode(list, cur);
9688 } else if ((cur->ns != NULL) &&
9689 (xmlStrEqual(URI, cur->ns->href))) {
9690 n++;
9691 if (n == indx)
9692 addNode(list, cur);
9693 }
9694 }
9695 }
9696 break;
9697 case NODE_TEST_NS:{
9698 TODO;
9699 break;
9700 }
9701 case NODE_TEST_NAME:
9702 switch (cur->type) {
9703 case XML_ELEMENT_NODE:
9704 if (xmlStrEqual(name, cur->name)) {
9705 if (prefix == NULL) {
9706 if (cur->ns == NULL) {
9707 n++;
9708 if (n == indx)
9709 addNode(list, cur);
9710 }
9711 } else {
9712 if ((cur->ns != NULL) &&
9713 (xmlStrEqual(URI,
9714 cur->ns->href))) {
9715 n++;
9716 if (n == indx)
9717 addNode(list, cur);
9718 }
9719 }
9720 }
9721 break;
9722 case XML_ATTRIBUTE_NODE:{
9723 xmlAttrPtr attr = (xmlAttrPtr) cur;
9724
9725 if (xmlStrEqual(name, attr->name)) {
9726 if (prefix == NULL) {
9727 if ((attr->ns == NULL) ||
9728 (attr->ns->prefix == NULL)) {
9729 n++;
9730 if (n == indx)
9731 addNode(list, cur);
9732 }
9733 } else {
9734 if ((attr->ns != NULL) &&
9735 (xmlStrEqual(URI,
9736 attr->ns->
9737 href))) {
9738 n++;
9739 if (n == indx)
9740 addNode(list, cur);
9741 }
9742 }
9743 }
9744 break;
9745 }
9746 case XML_NAMESPACE_DECL:
9747 if (cur->type == XML_NAMESPACE_DECL) {
9748 xmlNsPtr ns = (xmlNsPtr) cur;
9749
9750 if ((ns->prefix != NULL) && (name != NULL)
9751 && (xmlStrEqual(ns->prefix, name))) {
9752 n++;
9753 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009754 xmlXPathNodeSetAddNs(list,
9755 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009756 }
9757 }
9758 break;
9759 default:
9760 break;
9761 }
9762 break;
9763 break;
9764 }
9765 } while (n < indx);
9766 }
9767 ctxt->context->node = tmp;
9768#ifdef DEBUG_STEP_NTH
9769 xmlGenericError(xmlGenericErrorContext,
9770 "\nExamined %d nodes, found %d nodes at that step\n",
9771 t, list->nodeNr);
9772#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009773 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009774 if ((obj->boolval) && (obj->user != NULL)) {
9775 ctxt->value->boolval = 1;
9776 ctxt->value->user = obj->user;
9777 obj->user = NULL;
9778 obj->boolval = 0;
9779 }
9780 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009781 return(t);
9782}
9783
9784/**
9785 * xmlXPathCompOpEvalFirst:
9786 * @ctxt: the XPath parser context with the compiled expression
9787 * @op: an XPath compiled operation
9788 * @first: the first elem found so far
9789 *
9790 * Evaluate the Precompiled XPath operation searching only the first
9791 * element in document order
9792 *
9793 * Returns the number of examined objects.
9794 */
9795static int
9796xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9797 xmlXPathStepOpPtr op, xmlNodePtr * first)
9798{
9799 int total = 0, cur;
9800 xmlXPathCompExprPtr comp;
9801 xmlXPathObjectPtr arg1, arg2;
9802
Daniel Veillard556c6682001-10-06 09:59:51 +00009803 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009804 comp = ctxt->comp;
9805 switch (op->op) {
9806 case XPATH_OP_END:
9807 return (0);
9808 case XPATH_OP_UNION:
9809 total =
9810 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9811 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009812 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009813 if ((ctxt->value != NULL)
9814 && (ctxt->value->type == XPATH_NODESET)
9815 && (ctxt->value->nodesetval != NULL)
9816 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9817 /*
9818 * limit tree traversing to first node in the result
9819 */
9820 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9821 *first = ctxt->value->nodesetval->nodeTab[0];
9822 }
9823 cur =
9824 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9825 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009826 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009827 CHECK_TYPE0(XPATH_NODESET);
9828 arg2 = valuePop(ctxt);
9829
9830 CHECK_TYPE0(XPATH_NODESET);
9831 arg1 = valuePop(ctxt);
9832
9833 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9834 arg2->nodesetval);
9835 valuePush(ctxt, arg1);
9836 xmlXPathFreeObject(arg2);
9837 /* optimizer */
9838 if (total > cur)
9839 xmlXPathCompSwap(op);
9840 return (total + cur);
9841 case XPATH_OP_ROOT:
9842 xmlXPathRoot(ctxt);
9843 return (0);
9844 case XPATH_OP_NODE:
9845 if (op->ch1 != -1)
9846 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009847 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009848 if (op->ch2 != -1)
9849 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009850 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009851 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9852 return (total);
9853 case XPATH_OP_RESET:
9854 if (op->ch1 != -1)
9855 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009856 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009857 if (op->ch2 != -1)
9858 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009859 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009860 ctxt->context->node = NULL;
9861 return (total);
9862 case XPATH_OP_COLLECT:{
9863 if (op->ch1 == -1)
9864 return (total);
9865
9866 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009867 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009868
9869 /*
9870 * Optimization for [n] selection where n is a number
9871 */
9872 if ((op->ch2 != -1) &&
9873 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9874 (comp->steps[op->ch2].ch1 == -1) &&
9875 (comp->steps[op->ch2].ch2 != -1) &&
9876 (comp->steps[comp->steps[op->ch2].ch2].op ==
9877 XPATH_OP_VALUE)) {
9878 xmlXPathObjectPtr val;
9879
9880 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9881 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9882 int indx = (int) val->floatval;
9883
9884 if (val->floatval == (float) indx) {
9885 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9886 first, NULL);
9887 return (total);
9888 }
9889 }
9890 }
9891 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9892 return (total);
9893 }
9894 case XPATH_OP_VALUE:
9895 valuePush(ctxt,
9896 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9897 return (0);
9898 case XPATH_OP_SORT:
9899 if (op->ch1 != -1)
9900 total +=
9901 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9902 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009903 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009904 if ((ctxt->value != NULL)
9905 && (ctxt->value->type == XPATH_NODESET)
9906 && (ctxt->value->nodesetval != NULL))
9907 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9908 return (total);
9909 default:
9910 return (xmlXPathCompOpEval(ctxt, op));
9911 }
9912}
9913
9914/**
9915 * xmlXPathCompOpEvalLast:
9916 * @ctxt: the XPath parser context with the compiled expression
9917 * @op: an XPath compiled operation
9918 * @last: the last elem found so far
9919 *
9920 * Evaluate the Precompiled XPath operation searching only the last
9921 * element in document order
9922 *
William M. Brack08171912003-12-29 02:52:11 +00009923 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +00009924 */
9925static int
9926xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9927 xmlNodePtr * last)
9928{
9929 int total = 0, cur;
9930 xmlXPathCompExprPtr comp;
9931 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +00009932 xmlNodePtr bak;
9933 xmlDocPtr bakd;
9934 int pp;
9935 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009936
Daniel Veillard556c6682001-10-06 09:59:51 +00009937 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009938 comp = ctxt->comp;
9939 switch (op->op) {
9940 case XPATH_OP_END:
9941 return (0);
9942 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +00009943 bakd = ctxt->context->doc;
9944 bak = ctxt->context->node;
9945 pp = ctxt->context->proximityPosition;
9946 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009947 total =
9948 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009949 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009950 if ((ctxt->value != NULL)
9951 && (ctxt->value->type == XPATH_NODESET)
9952 && (ctxt->value->nodesetval != NULL)
9953 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9954 /*
9955 * limit tree traversing to first node in the result
9956 */
9957 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9958 *last =
9959 ctxt->value->nodesetval->nodeTab[ctxt->value->
9960 nodesetval->nodeNr -
9961 1];
9962 }
William M. Brackce4fc562004-01-22 02:47:18 +00009963 ctxt->context->doc = bakd;
9964 ctxt->context->node = bak;
9965 ctxt->context->proximityPosition = pp;
9966 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009967 cur =
9968 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009969 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009970 if ((ctxt->value != NULL)
9971 && (ctxt->value->type == XPATH_NODESET)
9972 && (ctxt->value->nodesetval != NULL)
9973 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9974 }
9975 CHECK_TYPE0(XPATH_NODESET);
9976 arg2 = valuePop(ctxt);
9977
9978 CHECK_TYPE0(XPATH_NODESET);
9979 arg1 = valuePop(ctxt);
9980
9981 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9982 arg2->nodesetval);
9983 valuePush(ctxt, arg1);
9984 xmlXPathFreeObject(arg2);
9985 /* optimizer */
9986 if (total > cur)
9987 xmlXPathCompSwap(op);
9988 return (total + cur);
9989 case XPATH_OP_ROOT:
9990 xmlXPathRoot(ctxt);
9991 return (0);
9992 case XPATH_OP_NODE:
9993 if (op->ch1 != -1)
9994 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009995 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009996 if (op->ch2 != -1)
9997 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009998 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009999 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10000 return (total);
10001 case XPATH_OP_RESET:
10002 if (op->ch1 != -1)
10003 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010004 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010005 if (op->ch2 != -1)
10006 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010007 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010008 ctxt->context->node = NULL;
10009 return (total);
10010 case XPATH_OP_COLLECT:{
10011 if (op->ch1 == -1)
10012 return (0);
10013
10014 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010015 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010016
10017 /*
10018 * Optimization for [n] selection where n is a number
10019 */
10020 if ((op->ch2 != -1) &&
10021 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10022 (comp->steps[op->ch2].ch1 == -1) &&
10023 (comp->steps[op->ch2].ch2 != -1) &&
10024 (comp->steps[comp->steps[op->ch2].ch2].op ==
10025 XPATH_OP_VALUE)) {
10026 xmlXPathObjectPtr val;
10027
10028 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10029 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10030 int indx = (int) val->floatval;
10031
10032 if (val->floatval == (float) indx) {
10033 total +=
10034 xmlXPathNodeCollectAndTestNth(ctxt, op,
10035 indx, NULL,
10036 last);
10037 return (total);
10038 }
10039 }
10040 }
10041 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10042 return (total);
10043 }
10044 case XPATH_OP_VALUE:
10045 valuePush(ctxt,
10046 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10047 return (0);
10048 case XPATH_OP_SORT:
10049 if (op->ch1 != -1)
10050 total +=
10051 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10052 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010053 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010054 if ((ctxt->value != NULL)
10055 && (ctxt->value->type == XPATH_NODESET)
10056 && (ctxt->value->nodesetval != NULL))
10057 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10058 return (total);
10059 default:
10060 return (xmlXPathCompOpEval(ctxt, op));
10061 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010062}
10063
Owen Taylor3473f882001-02-23 17:55:21 +000010064/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010065 * xmlXPathCompOpEval:
10066 * @ctxt: the XPath parser context with the compiled expression
10067 * @op: an XPath compiled operation
10068 *
10069 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010070 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010071 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010072static int
10073xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10074{
10075 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010076 int equal, ret;
10077 xmlXPathCompExprPtr comp;
10078 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010079 xmlNodePtr bak;
10080 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010081 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010082 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010083
Daniel Veillard556c6682001-10-06 09:59:51 +000010084 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010085 comp = ctxt->comp;
10086 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010087 case XPATH_OP_END:
10088 return (0);
10089 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010090 bakd = ctxt->context->doc;
10091 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010092 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010093 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010094 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010095 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010096 xmlXPathBooleanFunction(ctxt, 1);
10097 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10098 return (total);
10099 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010100 ctxt->context->doc = bakd;
10101 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010102 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010103 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010104 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010105 if (ctxt->error) {
10106 xmlXPathFreeObject(arg2);
10107 return(0);
10108 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010109 xmlXPathBooleanFunction(ctxt, 1);
10110 arg1 = valuePop(ctxt);
10111 arg1->boolval &= arg2->boolval;
10112 valuePush(ctxt, arg1);
10113 xmlXPathFreeObject(arg2);
10114 return (total);
10115 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010116 bakd = ctxt->context->doc;
10117 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010118 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010119 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010120 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010121 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010122 xmlXPathBooleanFunction(ctxt, 1);
10123 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10124 return (total);
10125 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010126 ctxt->context->doc = bakd;
10127 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010128 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010129 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010130 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010131 if (ctxt->error) {
10132 xmlXPathFreeObject(arg2);
10133 return(0);
10134 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010135 xmlXPathBooleanFunction(ctxt, 1);
10136 arg1 = valuePop(ctxt);
10137 arg1->boolval |= arg2->boolval;
10138 valuePush(ctxt, arg1);
10139 xmlXPathFreeObject(arg2);
10140 return (total);
10141 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010142 bakd = ctxt->context->doc;
10143 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010144 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010145 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010146 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010147 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010148 ctxt->context->doc = bakd;
10149 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010150 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010151 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010152 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010153 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010154 if (op->value)
10155 equal = xmlXPathEqualValues(ctxt);
10156 else
10157 equal = xmlXPathNotEqualValues(ctxt);
10158 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010159 return (total);
10160 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010161 bakd = ctxt->context->doc;
10162 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010163 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010164 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010165 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010166 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010167 ctxt->context->doc = bakd;
10168 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010169 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010170 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010171 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010172 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010173 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10174 valuePush(ctxt, xmlXPathNewBoolean(ret));
10175 return (total);
10176 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010177 bakd = ctxt->context->doc;
10178 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010179 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010180 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010181 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010182 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010183 if (op->ch2 != -1) {
10184 ctxt->context->doc = bakd;
10185 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010186 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010187 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010188 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010189 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010190 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010191 if (op->value == 0)
10192 xmlXPathSubValues(ctxt);
10193 else if (op->value == 1)
10194 xmlXPathAddValues(ctxt);
10195 else if (op->value == 2)
10196 xmlXPathValueFlipSign(ctxt);
10197 else if (op->value == 3) {
10198 CAST_TO_NUMBER;
10199 CHECK_TYPE0(XPATH_NUMBER);
10200 }
10201 return (total);
10202 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010203 bakd = ctxt->context->doc;
10204 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010205 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010206 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010207 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010208 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010209 ctxt->context->doc = bakd;
10210 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010211 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010212 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010213 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010214 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010215 if (op->value == 0)
10216 xmlXPathMultValues(ctxt);
10217 else if (op->value == 1)
10218 xmlXPathDivValues(ctxt);
10219 else if (op->value == 2)
10220 xmlXPathModValues(ctxt);
10221 return (total);
10222 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010223 bakd = ctxt->context->doc;
10224 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010225 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010226 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010227 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010228 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010229 ctxt->context->doc = bakd;
10230 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010231 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010232 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010233 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010234 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010235 CHECK_TYPE0(XPATH_NODESET);
10236 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010237
Daniel Veillardf06307e2001-07-03 10:35:50 +000010238 CHECK_TYPE0(XPATH_NODESET);
10239 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010240
Daniel Veillardf06307e2001-07-03 10:35:50 +000010241 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10242 arg2->nodesetval);
10243 valuePush(ctxt, arg1);
10244 xmlXPathFreeObject(arg2);
10245 return (total);
10246 case XPATH_OP_ROOT:
10247 xmlXPathRoot(ctxt);
10248 return (total);
10249 case XPATH_OP_NODE:
10250 if (op->ch1 != -1)
10251 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010252 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010253 if (op->ch2 != -1)
10254 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010255 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010256 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10257 return (total);
10258 case XPATH_OP_RESET:
10259 if (op->ch1 != -1)
10260 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010261 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010262 if (op->ch2 != -1)
10263 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010264 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010265 ctxt->context->node = NULL;
10266 return (total);
10267 case XPATH_OP_COLLECT:{
10268 if (op->ch1 == -1)
10269 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010270
Daniel Veillardf06307e2001-07-03 10:35:50 +000010271 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010272 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010273
Daniel Veillardf06307e2001-07-03 10:35:50 +000010274 /*
10275 * Optimization for [n] selection where n is a number
10276 */
10277 if ((op->ch2 != -1) &&
10278 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10279 (comp->steps[op->ch2].ch1 == -1) &&
10280 (comp->steps[op->ch2].ch2 != -1) &&
10281 (comp->steps[comp->steps[op->ch2].ch2].op ==
10282 XPATH_OP_VALUE)) {
10283 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010284
Daniel Veillardf06307e2001-07-03 10:35:50 +000010285 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10286 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10287 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010288
Daniel Veillardf06307e2001-07-03 10:35:50 +000010289 if (val->floatval == (float) indx) {
10290 total +=
10291 xmlXPathNodeCollectAndTestNth(ctxt, op,
10292 indx, NULL,
10293 NULL);
10294 return (total);
10295 }
10296 }
10297 }
10298 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10299 return (total);
10300 }
10301 case XPATH_OP_VALUE:
10302 valuePush(ctxt,
10303 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10304 return (total);
10305 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010306 xmlXPathObjectPtr val;
10307
Daniel Veillardf06307e2001-07-03 10:35:50 +000010308 if (op->ch1 != -1)
10309 total +=
10310 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010311 if (op->value5 == NULL) {
10312 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10313 if (val == NULL) {
10314 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10315 return(0);
10316 }
10317 valuePush(ctxt, val);
10318 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010319 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010320
Daniel Veillardf06307e2001-07-03 10:35:50 +000010321 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10322 if (URI == NULL) {
10323 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010324 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010325 op->value4, op->value5);
10326 return (total);
10327 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010328 val = xmlXPathVariableLookupNS(ctxt->context,
10329 op->value4, URI);
10330 if (val == NULL) {
10331 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10332 return(0);
10333 }
10334 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010335 }
10336 return (total);
10337 }
10338 case XPATH_OP_FUNCTION:{
10339 xmlXPathFunction func;
10340 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010341 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010342
10343 if (op->ch1 != -1)
10344 total +=
10345 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010346 if (ctxt->valueNr < op->value) {
10347 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010348 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010349 ctxt->error = XPATH_INVALID_OPERAND;
10350 return (total);
10351 }
10352 for (i = 0; i < op->value; i++)
10353 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10354 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010355 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010356 ctxt->error = XPATH_INVALID_OPERAND;
10357 return (total);
10358 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010359 if (op->cache != NULL)
10360 func = (xmlXPathFunction) op->cache;
10361 else {
10362 const xmlChar *URI = NULL;
10363
10364 if (op->value5 == NULL)
10365 func =
10366 xmlXPathFunctionLookup(ctxt->context,
10367 op->value4);
10368 else {
10369 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10370 if (URI == NULL) {
10371 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010372 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010373 op->value4, op->value5);
10374 return (total);
10375 }
10376 func = xmlXPathFunctionLookupNS(ctxt->context,
10377 op->value4, URI);
10378 }
10379 if (func == NULL) {
10380 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010381 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010382 op->value4);
10383 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010384 }
10385 op->cache = (void *) func;
10386 op->cacheURI = (void *) URI;
10387 }
10388 oldFunc = ctxt->context->function;
10389 oldFuncURI = ctxt->context->functionURI;
10390 ctxt->context->function = op->value4;
10391 ctxt->context->functionURI = op->cacheURI;
10392 func(ctxt, op->value);
10393 ctxt->context->function = oldFunc;
10394 ctxt->context->functionURI = oldFuncURI;
10395 return (total);
10396 }
10397 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010398 bakd = ctxt->context->doc;
10399 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010400 if (op->ch1 != -1)
10401 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010402 ctxt->context->doc = bakd;
10403 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010404 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010405 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010406 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010407 ctxt->context->doc = bakd;
10408 ctxt->context->node = bak;
10409 CHECK_ERROR0;
10410 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010411 return (total);
10412 case XPATH_OP_PREDICATE:
10413 case XPATH_OP_FILTER:{
10414 xmlXPathObjectPtr res;
10415 xmlXPathObjectPtr obj, tmp;
10416 xmlNodeSetPtr newset = NULL;
10417 xmlNodeSetPtr oldset;
10418 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000010419 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010420 int i;
10421
10422 /*
10423 * Optimization for ()[1] selection i.e. the first elem
10424 */
10425 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10426 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10427 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10428 xmlXPathObjectPtr val;
10429
10430 val = comp->steps[op->ch2].value4;
10431 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10432 (val->floatval == 1.0)) {
10433 xmlNodePtr first = NULL;
10434
10435 total +=
10436 xmlXPathCompOpEvalFirst(ctxt,
10437 &comp->steps[op->ch1],
10438 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010439 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010440 /*
10441 * The nodeset should be in document order,
10442 * Keep only the first value
10443 */
10444 if ((ctxt->value != NULL) &&
10445 (ctxt->value->type == XPATH_NODESET) &&
10446 (ctxt->value->nodesetval != NULL) &&
10447 (ctxt->value->nodesetval->nodeNr > 1))
10448 ctxt->value->nodesetval->nodeNr = 1;
10449 return (total);
10450 }
10451 }
10452 /*
10453 * Optimization for ()[last()] selection i.e. the last elem
10454 */
10455 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10456 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10457 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10458 int f = comp->steps[op->ch2].ch1;
10459
10460 if ((f != -1) &&
10461 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10462 (comp->steps[f].value5 == NULL) &&
10463 (comp->steps[f].value == 0) &&
10464 (comp->steps[f].value4 != NULL) &&
10465 (xmlStrEqual
10466 (comp->steps[f].value4, BAD_CAST "last"))) {
10467 xmlNodePtr last = NULL;
10468
10469 total +=
10470 xmlXPathCompOpEvalLast(ctxt,
10471 &comp->steps[op->ch1],
10472 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010473 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010474 /*
10475 * The nodeset should be in document order,
10476 * Keep only the last value
10477 */
10478 if ((ctxt->value != NULL) &&
10479 (ctxt->value->type == XPATH_NODESET) &&
10480 (ctxt->value->nodesetval != NULL) &&
10481 (ctxt->value->nodesetval->nodeTab != NULL) &&
10482 (ctxt->value->nodesetval->nodeNr > 1)) {
10483 ctxt->value->nodesetval->nodeTab[0] =
10484 ctxt->value->nodesetval->nodeTab[ctxt->
10485 value->
10486 nodesetval->
10487 nodeNr -
10488 1];
10489 ctxt->value->nodesetval->nodeNr = 1;
10490 }
10491 return (total);
10492 }
10493 }
10494
10495 if (op->ch1 != -1)
10496 total +=
10497 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010498 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010499 if (op->ch2 == -1)
10500 return (total);
10501 if (ctxt->value == NULL)
10502 return (total);
10503
10504 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010505
10506#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010507 /*
10508 * Hum are we filtering the result of an XPointer expression
10509 */
10510 if (ctxt->value->type == XPATH_LOCATIONSET) {
10511 xmlLocationSetPtr newlocset = NULL;
10512 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010513
Daniel Veillardf06307e2001-07-03 10:35:50 +000010514 /*
10515 * Extract the old locset, and then evaluate the result of the
10516 * expression for all the element in the locset. use it to grow
10517 * up a new locset.
10518 */
10519 CHECK_TYPE0(XPATH_LOCATIONSET);
10520 obj = valuePop(ctxt);
10521 oldlocset = obj->user;
10522 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010523
Daniel Veillardf06307e2001-07-03 10:35:50 +000010524 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10525 ctxt->context->contextSize = 0;
10526 ctxt->context->proximityPosition = 0;
10527 if (op->ch2 != -1)
10528 total +=
10529 xmlXPathCompOpEval(ctxt,
10530 &comp->steps[op->ch2]);
10531 res = valuePop(ctxt);
10532 if (res != NULL)
10533 xmlXPathFreeObject(res);
10534 valuePush(ctxt, obj);
10535 CHECK_ERROR0;
10536 return (total);
10537 }
10538 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010539
Daniel Veillardf06307e2001-07-03 10:35:50 +000010540 for (i = 0; i < oldlocset->locNr; i++) {
10541 /*
10542 * Run the evaluation with a node list made of a
10543 * single item in the nodelocset.
10544 */
10545 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010546 ctxt->context->contextSize = oldlocset->locNr;
10547 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010548 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10549 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010550
Daniel Veillardf06307e2001-07-03 10:35:50 +000010551 if (op->ch2 != -1)
10552 total +=
10553 xmlXPathCompOpEval(ctxt,
10554 &comp->steps[op->ch2]);
10555 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010556
Daniel Veillardf06307e2001-07-03 10:35:50 +000010557 /*
10558 * The result of the evaluation need to be tested to
10559 * decided whether the filter succeeded or not
10560 */
10561 res = valuePop(ctxt);
10562 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10563 xmlXPtrLocationSetAdd(newlocset,
10564 xmlXPathObjectCopy
10565 (oldlocset->locTab[i]));
10566 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010567
Daniel Veillardf06307e2001-07-03 10:35:50 +000010568 /*
10569 * Cleanup
10570 */
10571 if (res != NULL)
10572 xmlXPathFreeObject(res);
10573 if (ctxt->value == tmp) {
10574 res = valuePop(ctxt);
10575 xmlXPathFreeObject(res);
10576 }
10577
10578 ctxt->context->node = NULL;
10579 }
10580
10581 /*
10582 * The result is used as the new evaluation locset.
10583 */
10584 xmlXPathFreeObject(obj);
10585 ctxt->context->node = NULL;
10586 ctxt->context->contextSize = -1;
10587 ctxt->context->proximityPosition = -1;
10588 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10589 ctxt->context->node = oldnode;
10590 return (total);
10591 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010592#endif /* LIBXML_XPTR_ENABLED */
10593
Daniel Veillardf06307e2001-07-03 10:35:50 +000010594 /*
10595 * Extract the old set, and then evaluate the result of the
10596 * expression for all the element in the set. use it to grow
10597 * up a new set.
10598 */
10599 CHECK_TYPE0(XPATH_NODESET);
10600 obj = valuePop(ctxt);
10601 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010602
Daniel Veillardf06307e2001-07-03 10:35:50 +000010603 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000010604 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010605 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010606
Daniel Veillardf06307e2001-07-03 10:35:50 +000010607 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10608 ctxt->context->contextSize = 0;
10609 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000010610/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000010611 if (op->ch2 != -1)
10612 total +=
10613 xmlXPathCompOpEval(ctxt,
10614 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010615 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010616 res = valuePop(ctxt);
10617 if (res != NULL)
10618 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000010619*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000010620 valuePush(ctxt, obj);
10621 ctxt->context->node = oldnode;
10622 CHECK_ERROR0;
10623 } else {
10624 /*
10625 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000010626 * Also set the xpath document in case things like
10627 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000010628 */
10629 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010630
Daniel Veillardf06307e2001-07-03 10:35:50 +000010631 for (i = 0; i < oldset->nodeNr; i++) {
10632 /*
10633 * Run the evaluation with a node list made of
10634 * a single item in the nodeset.
10635 */
10636 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000010637 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
10638 (oldset->nodeTab[i]->doc != NULL))
10639 ctxt->context->doc = oldset->nodeTab[i]->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010640 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10641 valuePush(ctxt, tmp);
10642 ctxt->context->contextSize = oldset->nodeNr;
10643 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010644
Daniel Veillardf06307e2001-07-03 10:35:50 +000010645 if (op->ch2 != -1)
10646 total +=
10647 xmlXPathCompOpEval(ctxt,
10648 &comp->steps[op->ch2]);
10649 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010650
Daniel Veillardf06307e2001-07-03 10:35:50 +000010651 /*
William M. Brack08171912003-12-29 02:52:11 +000010652 * The result of the evaluation needs to be tested to
10653 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010654 */
10655 res = valuePop(ctxt);
10656 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10657 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10658 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010659
Daniel Veillardf06307e2001-07-03 10:35:50 +000010660 /*
10661 * Cleanup
10662 */
10663 if (res != NULL)
10664 xmlXPathFreeObject(res);
10665 if (ctxt->value == tmp) {
10666 res = valuePop(ctxt);
10667 xmlXPathFreeObject(res);
10668 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010669
Daniel Veillardf06307e2001-07-03 10:35:50 +000010670 ctxt->context->node = NULL;
10671 }
10672
10673 /*
10674 * The result is used as the new evaluation set.
10675 */
10676 xmlXPathFreeObject(obj);
10677 ctxt->context->node = NULL;
10678 ctxt->context->contextSize = -1;
10679 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000010680 /* may want to move this past the '}' later */
10681 ctxt->context->doc = oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010682 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10683 }
10684 ctxt->context->node = oldnode;
10685 return (total);
10686 }
10687 case XPATH_OP_SORT:
10688 if (op->ch1 != -1)
10689 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010690 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010691 if ((ctxt->value != NULL) &&
10692 (ctxt->value->type == XPATH_NODESET) &&
10693 (ctxt->value->nodesetval != NULL))
10694 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10695 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010696#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010697 case XPATH_OP_RANGETO:{
10698 xmlXPathObjectPtr range;
10699 xmlXPathObjectPtr res, obj;
10700 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010701 xmlLocationSetPtr newlocset = NULL;
10702 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010703 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000010704 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010705
Daniel Veillardf06307e2001-07-03 10:35:50 +000010706 if (op->ch1 != -1)
10707 total +=
10708 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10709 if (op->ch2 == -1)
10710 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010711
William M. Brack08171912003-12-29 02:52:11 +000010712 if (ctxt->value->type == XPATH_LOCATIONSET) {
10713 /*
10714 * Extract the old locset, and then evaluate the result of the
10715 * expression for all the element in the locset. use it to grow
10716 * up a new locset.
10717 */
10718 CHECK_TYPE0(XPATH_LOCATIONSET);
10719 obj = valuePop(ctxt);
10720 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010721
William M. Brack08171912003-12-29 02:52:11 +000010722 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000010723 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000010724 ctxt->context->contextSize = 0;
10725 ctxt->context->proximityPosition = 0;
10726 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10727 res = valuePop(ctxt);
10728 if (res != NULL)
10729 xmlXPathFreeObject(res);
10730 valuePush(ctxt, obj);
10731 CHECK_ERROR0;
10732 return (total);
10733 }
10734 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010735
William M. Brack08171912003-12-29 02:52:11 +000010736 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010737 /*
William M. Brack08171912003-12-29 02:52:11 +000010738 * Run the evaluation with a node list made of a
10739 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010740 */
William M. Brackf7eb7942003-12-31 07:59:17 +000010741 ctxt->context->node = oldlocset->locTab[i]->user;
10742 ctxt->context->contextSize = oldlocset->locNr;
10743 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010744 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10745 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010746
Daniel Veillardf06307e2001-07-03 10:35:50 +000010747 if (op->ch2 != -1)
10748 total +=
10749 xmlXPathCompOpEval(ctxt,
10750 &comp->steps[op->ch2]);
10751 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010752
Daniel Veillardf06307e2001-07-03 10:35:50 +000010753 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000010754 if (res->type == XPATH_LOCATIONSET) {
10755 xmlLocationSetPtr rloc =
10756 (xmlLocationSetPtr)res->user;
10757 for (j=0; j<rloc->locNr; j++) {
10758 range = xmlXPtrNewRange(
10759 oldlocset->locTab[i]->user,
10760 oldlocset->locTab[i]->index,
10761 rloc->locTab[j]->user2,
10762 rloc->locTab[j]->index2);
10763 if (range != NULL) {
10764 xmlXPtrLocationSetAdd(newlocset, range);
10765 }
10766 }
10767 } else {
10768 range = xmlXPtrNewRangeNodeObject(
10769 (xmlNodePtr)oldlocset->locTab[i]->user, res);
10770 if (range != NULL) {
10771 xmlXPtrLocationSetAdd(newlocset,range);
10772 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010773 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010774
Daniel Veillardf06307e2001-07-03 10:35:50 +000010775 /*
10776 * Cleanup
10777 */
10778 if (res != NULL)
10779 xmlXPathFreeObject(res);
10780 if (ctxt->value == tmp) {
10781 res = valuePop(ctxt);
10782 xmlXPathFreeObject(res);
10783 }
10784
10785 ctxt->context->node = NULL;
10786 }
William M. Brack72ee48d2003-12-30 08:30:19 +000010787 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000010788 CHECK_TYPE0(XPATH_NODESET);
10789 obj = valuePop(ctxt);
10790 oldset = obj->nodesetval;
10791 ctxt->context->node = NULL;
10792
10793 newlocset = xmlXPtrLocationSetCreate(NULL);
10794
10795 if (oldset != NULL) {
10796 for (i = 0; i < oldset->nodeNr; i++) {
10797 /*
10798 * Run the evaluation with a node list made of a single item
10799 * in the nodeset.
10800 */
10801 ctxt->context->node = oldset->nodeTab[i];
10802 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10803 valuePush(ctxt, tmp);
10804
10805 if (op->ch2 != -1)
10806 total +=
10807 xmlXPathCompOpEval(ctxt,
10808 &comp->steps[op->ch2]);
10809 CHECK_ERROR0;
10810
William M. Brack08171912003-12-29 02:52:11 +000010811 res = valuePop(ctxt);
10812 range =
10813 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10814 res);
10815 if (range != NULL) {
10816 xmlXPtrLocationSetAdd(newlocset, range);
10817 }
10818
10819 /*
10820 * Cleanup
10821 */
10822 if (res != NULL)
10823 xmlXPathFreeObject(res);
10824 if (ctxt->value == tmp) {
10825 res = valuePop(ctxt);
10826 xmlXPathFreeObject(res);
10827 }
10828
10829 ctxt->context->node = NULL;
10830 }
10831 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010832 }
10833
10834 /*
10835 * The result is used as the new evaluation set.
10836 */
10837 xmlXPathFreeObject(obj);
10838 ctxt->context->node = NULL;
10839 ctxt->context->contextSize = -1;
10840 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010841 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010842 return (total);
10843 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010844#endif /* LIBXML_XPTR_ENABLED */
10845 }
10846 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010847 "XPath: unknown precompiled operation %d\n", op->op);
10848 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010849}
10850
10851/**
10852 * xmlXPathRunEval:
10853 * @ctxt: the XPath parser context with the compiled expression
10854 *
10855 * Evaluate the Precompiled XPath expression in the given context.
10856 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010857static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010858xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10859 xmlXPathCompExprPtr comp;
10860
10861 if ((ctxt == NULL) || (ctxt->comp == NULL))
10862 return;
10863
10864 if (ctxt->valueTab == NULL) {
10865 /* Allocate the value stack */
10866 ctxt->valueTab = (xmlXPathObjectPtr *)
10867 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10868 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010869 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010870 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010871 }
10872 ctxt->valueNr = 0;
10873 ctxt->valueMax = 10;
10874 ctxt->value = NULL;
10875 }
10876 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010877 if(comp->last < 0) {
10878 xmlGenericError(xmlGenericErrorContext,
10879 "xmlXPathRunEval: last is less than zero\n");
10880 return;
10881 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010882 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10883}
10884
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010885/************************************************************************
10886 * *
10887 * Public interfaces *
10888 * *
10889 ************************************************************************/
10890
10891/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010892 * xmlXPathEvalPredicate:
10893 * @ctxt: the XPath context
10894 * @res: the Predicate Expression evaluation result
10895 *
10896 * Evaluate a predicate result for the current node.
10897 * A PredicateExpr is evaluated by evaluating the Expr and converting
10898 * the result to a boolean. If the result is a number, the result will
10899 * be converted to true if the number is equal to the position of the
10900 * context node in the context node list (as returned by the position
10901 * function) and will be converted to false otherwise; if the result
10902 * is not a number, then the result will be converted as if by a call
10903 * to the boolean function.
10904 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010905 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010906 */
10907int
10908xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000010909 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010910 switch (res->type) {
10911 case XPATH_BOOLEAN:
10912 return(res->boolval);
10913 case XPATH_NUMBER:
10914 return(res->floatval == ctxt->proximityPosition);
10915 case XPATH_NODESET:
10916 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010917 if (res->nodesetval == NULL)
10918 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010919 return(res->nodesetval->nodeNr != 0);
10920 case XPATH_STRING:
10921 return((res->stringval != NULL) &&
10922 (xmlStrlen(res->stringval) != 0));
10923 default:
10924 STRANGE
10925 }
10926 return(0);
10927}
10928
10929/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010930 * xmlXPathEvaluatePredicateResult:
10931 * @ctxt: the XPath Parser context
10932 * @res: the Predicate Expression evaluation result
10933 *
10934 * Evaluate a predicate result for the current node.
10935 * A PredicateExpr is evaluated by evaluating the Expr and converting
10936 * the result to a boolean. If the result is a number, the result will
10937 * be converted to true if the number is equal to the position of the
10938 * context node in the context node list (as returned by the position
10939 * function) and will be converted to false otherwise; if the result
10940 * is not a number, then the result will be converted as if by a call
10941 * to the boolean function.
10942 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010943 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010944 */
10945int
10946xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10947 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000010948 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010949 switch (res->type) {
10950 case XPATH_BOOLEAN:
10951 return(res->boolval);
10952 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000010953#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000010954 return((res->floatval == ctxt->context->proximityPosition) &&
10955 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000010956#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010957 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000010958#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010959 case XPATH_NODESET:
10960 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010961 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010962 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010963 return(res->nodesetval->nodeNr != 0);
10964 case XPATH_STRING:
10965 return((res->stringval != NULL) &&
10966 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000010967#ifdef LIBXML_XPTR_ENABLED
10968 case XPATH_LOCATIONSET:{
10969 xmlLocationSetPtr ptr = res->user;
10970 if (ptr == NULL)
10971 return(0);
10972 return (ptr->locNr != 0);
10973 }
10974#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010975 default:
10976 STRANGE
10977 }
10978 return(0);
10979}
10980
10981/**
Daniel Veillard4773df22004-01-23 13:15:13 +000010982 * xmlXPathCtxtCompile:
10983 * @ctxt: an XPath context
10984 * @str: the XPath expression
10985 *
10986 * Compile an XPath expression
10987 *
10988 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
10989 * the caller has to free the object.
10990 */
10991xmlXPathCompExprPtr
10992xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
10993 xmlXPathParserContextPtr pctxt;
10994 xmlXPathCompExprPtr comp;
10995
10996 xmlXPathInit();
10997
10998 pctxt = xmlXPathNewParserContext(str, ctxt);
10999 xmlXPathCompileExpr(pctxt);
11000
11001 if( pctxt->error != XPATH_EXPRESSION_OK )
11002 {
11003 xmlXPathFreeParserContext(pctxt);
11004 return (0);
11005 }
11006
11007 if (*pctxt->cur != 0) {
11008 /*
11009 * aleksey: in some cases this line prints *second* error message
11010 * (see bug #78858) and probably this should be fixed.
11011 * However, we are not sure that all error messages are printed
11012 * out in other places. It's not critical so we leave it as-is for now
11013 */
11014 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11015 comp = NULL;
11016 } else {
11017 comp = pctxt->comp;
11018 pctxt->comp = NULL;
11019 }
11020 xmlXPathFreeParserContext(pctxt);
11021 if (comp != NULL) {
11022 comp->expr = xmlStrdup(str);
11023#ifdef DEBUG_EVAL_COUNTS
11024 comp->string = xmlStrdup(str);
11025 comp->nb = 0;
11026#endif
11027 }
11028 return(comp);
11029}
11030
11031/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011032 * xmlXPathCompile:
11033 * @str: the XPath expression
11034 *
11035 * Compile an XPath expression
11036 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000011037 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011038 * the caller has to free the object.
11039 */
11040xmlXPathCompExprPtr
11041xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000011042 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011043}
11044
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011045/**
11046 * xmlXPathCompiledEval:
11047 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000011048 * @ctx: the XPath context
11049 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011050 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000011051 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011052 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000011053 * the caller has to free the object.
11054 */
11055xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011056xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000011057 xmlXPathParserContextPtr ctxt;
11058 xmlXPathObjectPtr res, tmp, init = NULL;
11059 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000011060#ifndef LIBXML_THREAD_ENABLED
11061 static int reentance = 0;
11062#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011063
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011064 if ((comp == NULL) || (ctx == NULL))
11065 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011066 xmlXPathInit();
11067
11068 CHECK_CONTEXT(ctx)
11069
Daniel Veillard81463942001-10-16 12:34:39 +000011070#ifndef LIBXML_THREAD_ENABLED
11071 reentance++;
11072 if (reentance > 1)
11073 xmlXPathDisableOptimizer = 1;
11074#endif
11075
Daniel Veillardf06307e2001-07-03 10:35:50 +000011076#ifdef DEBUG_EVAL_COUNTS
11077 comp->nb++;
11078 if ((comp->string != NULL) && (comp->nb > 100)) {
11079 fprintf(stderr, "100 x %s\n", comp->string);
11080 comp->nb = 0;
11081 }
11082#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011083 ctxt = xmlXPathCompParserContext(comp, ctx);
11084 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011085
11086 if (ctxt->value == NULL) {
11087 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011088 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011089 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011090 } else {
11091 res = valuePop(ctxt);
11092 }
11093
Daniel Veillardf06307e2001-07-03 10:35:50 +000011094
Owen Taylor3473f882001-02-23 17:55:21 +000011095 do {
11096 tmp = valuePop(ctxt);
11097 if (tmp != NULL) {
11098 if (tmp != init)
11099 stack++;
11100 xmlXPathFreeObject(tmp);
11101 }
11102 } while (tmp != NULL);
11103 if ((stack != 0) && (res != NULL)) {
11104 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011105 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011106 stack);
11107 }
11108 if (ctxt->error != XPATH_EXPRESSION_OK) {
11109 xmlXPathFreeObject(res);
11110 res = NULL;
11111 }
11112
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011113
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011114 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011115 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011116#ifndef LIBXML_THREAD_ENABLED
11117 reentance--;
11118#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011119 return(res);
11120}
11121
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011122/**
11123 * xmlXPathEvalExpr:
11124 * @ctxt: the XPath Parser context
11125 *
11126 * Parse and evaluate an XPath expression in the given context,
11127 * then push the result on the context stack
11128 */
11129void
11130xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
11131 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011132 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011133 xmlXPathRunEval(ctxt);
11134}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011135
11136/**
11137 * xmlXPathEval:
11138 * @str: the XPath expression
11139 * @ctx: the XPath context
11140 *
11141 * Evaluate the XPath Location Path in the given context.
11142 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011143 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011144 * the caller has to free the object.
11145 */
11146xmlXPathObjectPtr
11147xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11148 xmlXPathParserContextPtr ctxt;
11149 xmlXPathObjectPtr res, tmp, init = NULL;
11150 int stack = 0;
11151
11152 xmlXPathInit();
11153
11154 CHECK_CONTEXT(ctx)
11155
11156 ctxt = xmlXPathNewParserContext(str, ctx);
11157 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011158
11159 if (ctxt->value == NULL) {
11160 xmlGenericError(xmlGenericErrorContext,
11161 "xmlXPathEval: evaluation failed\n");
11162 res = NULL;
11163 } else if (*ctxt->cur != 0) {
11164 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11165 res = NULL;
11166 } else {
11167 res = valuePop(ctxt);
11168 }
11169
11170 do {
11171 tmp = valuePop(ctxt);
11172 if (tmp != NULL) {
11173 if (tmp != init)
11174 stack++;
11175 xmlXPathFreeObject(tmp);
11176 }
11177 } while (tmp != NULL);
11178 if ((stack != 0) && (res != NULL)) {
11179 xmlGenericError(xmlGenericErrorContext,
11180 "xmlXPathEval: %d object left on the stack\n",
11181 stack);
11182 }
11183 if (ctxt->error != XPATH_EXPRESSION_OK) {
11184 xmlXPathFreeObject(res);
11185 res = NULL;
11186 }
11187
Owen Taylor3473f882001-02-23 17:55:21 +000011188 xmlXPathFreeParserContext(ctxt);
11189 return(res);
11190}
11191
11192/**
11193 * xmlXPathEvalExpression:
11194 * @str: the XPath expression
11195 * @ctxt: the XPath context
11196 *
11197 * Evaluate the XPath expression in the given context.
11198 *
11199 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11200 * the caller has to free the object.
11201 */
11202xmlXPathObjectPtr
11203xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11204 xmlXPathParserContextPtr pctxt;
11205 xmlXPathObjectPtr res, tmp;
11206 int stack = 0;
11207
11208 xmlXPathInit();
11209
11210 CHECK_CONTEXT(ctxt)
11211
11212 pctxt = xmlXPathNewParserContext(str, ctxt);
11213 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011214
11215 if (*pctxt->cur != 0) {
11216 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11217 res = NULL;
11218 } else {
11219 res = valuePop(pctxt);
11220 }
11221 do {
11222 tmp = valuePop(pctxt);
11223 if (tmp != NULL) {
11224 xmlXPathFreeObject(tmp);
11225 stack++;
11226 }
11227 } while (tmp != NULL);
11228 if ((stack != 0) && (res != NULL)) {
11229 xmlGenericError(xmlGenericErrorContext,
11230 "xmlXPathEvalExpression: %d object left on the stack\n",
11231 stack);
11232 }
11233 xmlXPathFreeParserContext(pctxt);
11234 return(res);
11235}
11236
Daniel Veillard42766c02002-08-22 20:52:17 +000011237/************************************************************************
11238 * *
11239 * Extra functions not pertaining to the XPath spec *
11240 * *
11241 ************************************************************************/
11242/**
11243 * xmlXPathEscapeUriFunction:
11244 * @ctxt: the XPath Parser context
11245 * @nargs: the number of arguments
11246 *
11247 * Implement the escape-uri() XPath function
11248 * string escape-uri(string $str, bool $escape-reserved)
11249 *
11250 * This function applies the URI escaping rules defined in section 2 of [RFC
11251 * 2396] to the string supplied as $uri-part, which typically represents all
11252 * or part of a URI. The effect of the function is to replace any special
11253 * character in the string by an escape sequence of the form %xx%yy...,
11254 * where xxyy... is the hexadecimal representation of the octets used to
11255 * represent the character in UTF-8.
11256 *
11257 * The set of characters that are escaped depends on the setting of the
11258 * boolean argument $escape-reserved.
11259 *
11260 * If $escape-reserved is true, all characters are escaped other than lower
11261 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11262 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11263 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11264 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11265 * A-F).
11266 *
11267 * If $escape-reserved is false, the behavior differs in that characters
11268 * referred to in [RFC 2396] as reserved characters are not escaped. These
11269 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11270 *
11271 * [RFC 2396] does not define whether escaped URIs should use lower case or
11272 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11273 * compared using string comparison functions, this function must always use
11274 * the upper-case letters A-F.
11275 *
11276 * Generally, $escape-reserved should be set to true when escaping a string
11277 * that is to form a single part of a URI, and to false when escaping an
11278 * entire URI or URI reference.
11279 *
11280 * In the case of non-ascii characters, the string is encoded according to
11281 * utf-8 and then converted according to RFC 2396.
11282 *
11283 * Examples
11284 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11285 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11286 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11287 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11288 *
11289 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011290static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011291xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11292 xmlXPathObjectPtr str;
11293 int escape_reserved;
11294 xmlBufferPtr target;
11295 xmlChar *cptr;
11296 xmlChar escape[4];
11297
11298 CHECK_ARITY(2);
11299
11300 escape_reserved = xmlXPathPopBoolean(ctxt);
11301
11302 CAST_TO_STRING;
11303 str = valuePop(ctxt);
11304
11305 target = xmlBufferCreate();
11306
11307 escape[0] = '%';
11308 escape[3] = 0;
11309
11310 if (target) {
11311 for (cptr = str->stringval; *cptr; cptr++) {
11312 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11313 (*cptr >= 'a' && *cptr <= 'z') ||
11314 (*cptr >= '0' && *cptr <= '9') ||
11315 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11316 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11317 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11318 (*cptr == '%' &&
11319 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11320 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11321 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11322 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11323 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11324 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11325 (!escape_reserved &&
11326 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11327 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11328 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11329 *cptr == ','))) {
11330 xmlBufferAdd(target, cptr, 1);
11331 } else {
11332 if ((*cptr >> 4) < 10)
11333 escape[1] = '0' + (*cptr >> 4);
11334 else
11335 escape[1] = 'A' - 10 + (*cptr >> 4);
11336 if ((*cptr & 0xF) < 10)
11337 escape[2] = '0' + (*cptr & 0xF);
11338 else
11339 escape[2] = 'A' - 10 + (*cptr & 0xF);
11340
11341 xmlBufferAdd(target, &escape[0], 3);
11342 }
11343 }
11344 }
11345 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11346 xmlBufferFree(target);
11347 xmlXPathFreeObject(str);
11348}
11349
Owen Taylor3473f882001-02-23 17:55:21 +000011350/**
11351 * xmlXPathRegisterAllFunctions:
11352 * @ctxt: the XPath context
11353 *
11354 * Registers all default XPath functions in this context
11355 */
11356void
11357xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11358{
11359 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11360 xmlXPathBooleanFunction);
11361 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11362 xmlXPathCeilingFunction);
11363 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11364 xmlXPathCountFunction);
11365 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11366 xmlXPathConcatFunction);
11367 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11368 xmlXPathContainsFunction);
11369 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11370 xmlXPathIdFunction);
11371 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11372 xmlXPathFalseFunction);
11373 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11374 xmlXPathFloorFunction);
11375 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11376 xmlXPathLastFunction);
11377 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11378 xmlXPathLangFunction);
11379 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11380 xmlXPathLocalNameFunction);
11381 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11382 xmlXPathNotFunction);
11383 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11384 xmlXPathNameFunction);
11385 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11386 xmlXPathNamespaceURIFunction);
11387 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11388 xmlXPathNormalizeFunction);
11389 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11390 xmlXPathNumberFunction);
11391 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11392 xmlXPathPositionFunction);
11393 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11394 xmlXPathRoundFunction);
11395 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11396 xmlXPathStringFunction);
11397 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11398 xmlXPathStringLengthFunction);
11399 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11400 xmlXPathStartsWithFunction);
11401 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11402 xmlXPathSubstringFunction);
11403 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11404 xmlXPathSubstringBeforeFunction);
11405 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11406 xmlXPathSubstringAfterFunction);
11407 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11408 xmlXPathSumFunction);
11409 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11410 xmlXPathTrueFunction);
11411 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11412 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011413
11414 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11415 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11416 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011417}
11418
11419#endif /* LIBXML_XPATH_ENABLED */