blob: 12d1346969a6b37c4c223273fc79ed181f83ce86 [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
Daniel Veillarda82b1822004-11-08 16:24:57 +0000778 if (output == NULL) return;
779
Owen Taylor3473f882001-02-23 17:55:21 +0000780 for (i = 0;((i < depth) && (i < 25));i++)
781 shift[2 * i] = shift[2 * i + 1] = ' ';
782 shift[2 * i] = shift[2 * i + 1] = 0;
783
784 fprintf(output, shift);
785
786 if (cur == NULL) {
787 fprintf(output, "Object is empty (NULL)\n");
788 return;
789 }
790 switch(cur->type) {
791 case XPATH_UNDEFINED:
792 fprintf(output, "Object is uninitialized\n");
793 break;
794 case XPATH_NODESET:
795 fprintf(output, "Object is a Node Set :\n");
796 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
797 break;
798 case XPATH_XSLT_TREE:
799 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000800 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000801 break;
802 case XPATH_BOOLEAN:
803 fprintf(output, "Object is a Boolean : ");
804 if (cur->boolval) fprintf(output, "true\n");
805 else fprintf(output, "false\n");
806 break;
807 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000808 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000809 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000810 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000811 break;
812 case -1:
813 fprintf(output, "Object is a number : -Infinity\n");
814 break;
815 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000816 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000817 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000818 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
819 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000820 } else {
821 fprintf(output, "Object is a number : %0g\n", cur->floatval);
822 }
823 }
Owen Taylor3473f882001-02-23 17:55:21 +0000824 break;
825 case XPATH_STRING:
826 fprintf(output, "Object is a string : ");
827 xmlDebugDumpString(output, cur->stringval);
828 fprintf(output, "\n");
829 break;
830 case XPATH_POINT:
831 fprintf(output, "Object is a point : index %d in node", cur->index);
832 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
833 fprintf(output, "\n");
834 break;
835 case XPATH_RANGE:
836 if ((cur->user2 == NULL) ||
837 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
838 fprintf(output, "Object is a collapsed range :\n");
839 fprintf(output, shift);
840 if (cur->index >= 0)
841 fprintf(output, "index %d in ", cur->index);
842 fprintf(output, "node\n");
843 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
844 depth + 1);
845 } else {
846 fprintf(output, "Object is a range :\n");
847 fprintf(output, shift);
848 fprintf(output, "From ");
849 if (cur->index >= 0)
850 fprintf(output, "index %d in ", cur->index);
851 fprintf(output, "node\n");
852 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
853 depth + 1);
854 fprintf(output, shift);
855 fprintf(output, "To ");
856 if (cur->index2 >= 0)
857 fprintf(output, "index %d in ", cur->index2);
858 fprintf(output, "node\n");
859 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
860 depth + 1);
861 fprintf(output, "\n");
862 }
863 break;
864 case XPATH_LOCATIONSET:
865#if defined(LIBXML_XPTR_ENABLED)
866 fprintf(output, "Object is a Location Set:\n");
867 xmlXPathDebugDumpLocationSet(output,
868 (xmlLocationSetPtr) cur->user, depth);
869#endif
870 break;
871 case XPATH_USERS:
872 fprintf(output, "Object is user defined\n");
873 break;
874 }
875}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000876
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000877static void
878xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000879 xmlXPathStepOpPtr op, int depth) {
880 int i;
881 char shift[100];
882
883 for (i = 0;((i < depth) && (i < 25));i++)
884 shift[2 * i] = shift[2 * i + 1] = ' ';
885 shift[2 * i] = shift[2 * i + 1] = 0;
886
887 fprintf(output, shift);
888 if (op == NULL) {
889 fprintf(output, "Step is NULL\n");
890 return;
891 }
892 switch (op->op) {
893 case XPATH_OP_END:
894 fprintf(output, "END"); break;
895 case XPATH_OP_AND:
896 fprintf(output, "AND"); break;
897 case XPATH_OP_OR:
898 fprintf(output, "OR"); break;
899 case XPATH_OP_EQUAL:
900 if (op->value)
901 fprintf(output, "EQUAL =");
902 else
903 fprintf(output, "EQUAL !=");
904 break;
905 case XPATH_OP_CMP:
906 if (op->value)
907 fprintf(output, "CMP <");
908 else
909 fprintf(output, "CMP >");
910 if (!op->value2)
911 fprintf(output, "=");
912 break;
913 case XPATH_OP_PLUS:
914 if (op->value == 0)
915 fprintf(output, "PLUS -");
916 else if (op->value == 1)
917 fprintf(output, "PLUS +");
918 else if (op->value == 2)
919 fprintf(output, "PLUS unary -");
920 else if (op->value == 3)
921 fprintf(output, "PLUS unary - -");
922 break;
923 case XPATH_OP_MULT:
924 if (op->value == 0)
925 fprintf(output, "MULT *");
926 else if (op->value == 1)
927 fprintf(output, "MULT div");
928 else
929 fprintf(output, "MULT mod");
930 break;
931 case XPATH_OP_UNION:
932 fprintf(output, "UNION"); break;
933 case XPATH_OP_ROOT:
934 fprintf(output, "ROOT"); break;
935 case XPATH_OP_NODE:
936 fprintf(output, "NODE"); break;
937 case XPATH_OP_RESET:
938 fprintf(output, "RESET"); break;
939 case XPATH_OP_SORT:
940 fprintf(output, "SORT"); break;
941 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000942 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
943 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
944 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000945 const xmlChar *prefix = op->value4;
946 const xmlChar *name = op->value5;
947
948 fprintf(output, "COLLECT ");
949 switch (axis) {
950 case AXIS_ANCESTOR:
951 fprintf(output, " 'ancestors' "); break;
952 case AXIS_ANCESTOR_OR_SELF:
953 fprintf(output, " 'ancestors-or-self' "); break;
954 case AXIS_ATTRIBUTE:
955 fprintf(output, " 'attributes' "); break;
956 case AXIS_CHILD:
957 fprintf(output, " 'child' "); break;
958 case AXIS_DESCENDANT:
959 fprintf(output, " 'descendant' "); break;
960 case AXIS_DESCENDANT_OR_SELF:
961 fprintf(output, " 'descendant-or-self' "); break;
962 case AXIS_FOLLOWING:
963 fprintf(output, " 'following' "); break;
964 case AXIS_FOLLOWING_SIBLING:
965 fprintf(output, " 'following-siblings' "); break;
966 case AXIS_NAMESPACE:
967 fprintf(output, " 'namespace' "); break;
968 case AXIS_PARENT:
969 fprintf(output, " 'parent' "); break;
970 case AXIS_PRECEDING:
971 fprintf(output, " 'preceding' "); break;
972 case AXIS_PRECEDING_SIBLING:
973 fprintf(output, " 'preceding-sibling' "); break;
974 case AXIS_SELF:
975 fprintf(output, " 'self' "); break;
976 }
977 switch (test) {
978 case NODE_TEST_NONE:
979 fprintf(output, "'none' "); break;
980 case NODE_TEST_TYPE:
981 fprintf(output, "'type' "); break;
982 case NODE_TEST_PI:
983 fprintf(output, "'PI' "); break;
984 case NODE_TEST_ALL:
985 fprintf(output, "'all' "); break;
986 case NODE_TEST_NS:
987 fprintf(output, "'namespace' "); break;
988 case NODE_TEST_NAME:
989 fprintf(output, "'name' "); break;
990 }
991 switch (type) {
992 case NODE_TYPE_NODE:
993 fprintf(output, "'node' "); break;
994 case NODE_TYPE_COMMENT:
995 fprintf(output, "'comment' "); break;
996 case NODE_TYPE_TEXT:
997 fprintf(output, "'text' "); break;
998 case NODE_TYPE_PI:
999 fprintf(output, "'PI' "); break;
1000 }
1001 if (prefix != NULL)
1002 fprintf(output, "%s:", prefix);
1003 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001004 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001005 break;
1006
1007 }
1008 case XPATH_OP_VALUE: {
1009 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1010
1011 fprintf(output, "ELEM ");
1012 xmlXPathDebugDumpObject(output, object, 0);
1013 goto finish;
1014 }
1015 case XPATH_OP_VARIABLE: {
1016 const xmlChar *prefix = op->value5;
1017 const xmlChar *name = op->value4;
1018
1019 if (prefix != NULL)
1020 fprintf(output, "VARIABLE %s:%s", prefix, name);
1021 else
1022 fprintf(output, "VARIABLE %s", name);
1023 break;
1024 }
1025 case XPATH_OP_FUNCTION: {
1026 int nbargs = op->value;
1027 const xmlChar *prefix = op->value5;
1028 const xmlChar *name = op->value4;
1029
1030 if (prefix != NULL)
1031 fprintf(output, "FUNCTION %s:%s(%d args)",
1032 prefix, name, nbargs);
1033 else
1034 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1035 break;
1036 }
1037 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1038 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001039 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001040#ifdef LIBXML_XPTR_ENABLED
1041 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1042#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001043 default:
1044 fprintf(output, "UNKNOWN %d\n", op->op); return;
1045 }
1046 fprintf(output, "\n");
1047finish:
1048 if (op->ch1 >= 0)
1049 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1050 if (op->ch2 >= 0)
1051 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1052}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001053
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001054/**
1055 * xmlXPathDebugDumpCompExpr:
1056 * @output: the FILE * for the output
1057 * @comp: the precompiled XPath expression
1058 * @depth: the indentation level.
1059 *
1060 * Dumps the tree of the compiled XPath expression.
1061 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001062void
1063xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1064 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001065 int i;
1066 char shift[100];
1067
Daniel Veillarda82b1822004-11-08 16:24:57 +00001068 if ((output == NULL) || (comp == NULL)) return;
1069
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001070 for (i = 0;((i < depth) && (i < 25));i++)
1071 shift[2 * i] = shift[2 * i + 1] = ' ';
1072 shift[2 * i] = shift[2 * i + 1] = 0;
1073
1074 fprintf(output, shift);
1075
1076 if (comp == NULL) {
1077 fprintf(output, "Compiled Expression is NULL\n");
1078 return;
1079 }
1080 fprintf(output, "Compiled Expression : %d elements\n",
1081 comp->nbStep);
1082 i = comp->last;
1083 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1084}
Daniel Veillard017b1082001-06-21 11:20:21 +00001085#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001086
1087/************************************************************************
1088 * *
1089 * Parser stacks related functions and macros *
1090 * *
1091 ************************************************************************/
1092
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001093/**
1094 * valuePop:
1095 * @ctxt: an XPath evaluation context
1096 *
1097 * Pops the top XPath object from the value stack
1098 *
1099 * Returns the XPath object just removed
1100 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001101extern xmlXPathObjectPtr
1102valuePop(xmlXPathParserContextPtr ctxt)
1103{
1104 xmlXPathObjectPtr ret;
1105
Daniel Veillarda82b1822004-11-08 16:24:57 +00001106 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard1c732d22002-11-30 11:22:59 +00001107 return (0);
1108 ctxt->valueNr--;
1109 if (ctxt->valueNr > 0)
1110 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1111 else
1112 ctxt->value = NULL;
1113 ret = ctxt->valueTab[ctxt->valueNr];
1114 ctxt->valueTab[ctxt->valueNr] = 0;
1115 return (ret);
1116}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001117/**
1118 * valuePush:
1119 * @ctxt: an XPath evaluation context
1120 * @value: the XPath object
1121 *
1122 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001123 *
1124 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001125 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001126extern int
1127valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1128{
Daniel Veillarda82b1822004-11-08 16:24:57 +00001129 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00001130 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001131 xmlXPathObjectPtr *tmp;
1132
1133 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1134 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00001135 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001136 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00001137 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1138 return (0);
1139 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001140 ctxt->valueMax *= 2;
1141 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00001142 }
1143 ctxt->valueTab[ctxt->valueNr] = value;
1144 ctxt->value = value;
1145 return (ctxt->valueNr++);
1146}
Owen Taylor3473f882001-02-23 17:55:21 +00001147
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001148/**
1149 * xmlXPathPopBoolean:
1150 * @ctxt: an XPath parser context
1151 *
1152 * Pops a boolean from the stack, handling conversion if needed.
1153 * Check error with #xmlXPathCheckError.
1154 *
1155 * Returns the boolean
1156 */
1157int
1158xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1159 xmlXPathObjectPtr obj;
1160 int ret;
1161
1162 obj = valuePop(ctxt);
1163 if (obj == NULL) {
1164 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1165 return(0);
1166 }
William M. Brack08171912003-12-29 02:52:11 +00001167 if (obj->type != XPATH_BOOLEAN)
1168 ret = xmlXPathCastToBoolean(obj);
1169 else
1170 ret = obj->boolval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001171 xmlXPathFreeObject(obj);
1172 return(ret);
1173}
1174
1175/**
1176 * xmlXPathPopNumber:
1177 * @ctxt: an XPath parser context
1178 *
1179 * Pops a number from the stack, handling conversion if needed.
1180 * Check error with #xmlXPathCheckError.
1181 *
1182 * Returns the number
1183 */
1184double
1185xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1186 xmlXPathObjectPtr obj;
1187 double ret;
1188
1189 obj = valuePop(ctxt);
1190 if (obj == NULL) {
1191 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1192 return(0);
1193 }
William M. Brack08171912003-12-29 02:52:11 +00001194 if (obj->type != XPATH_NUMBER)
1195 ret = xmlXPathCastToNumber(obj);
1196 else
1197 ret = obj->floatval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001198 xmlXPathFreeObject(obj);
1199 return(ret);
1200}
1201
1202/**
1203 * xmlXPathPopString:
1204 * @ctxt: an XPath parser context
1205 *
1206 * Pops a string from the stack, handling conversion if needed.
1207 * Check error with #xmlXPathCheckError.
1208 *
1209 * Returns the string
1210 */
1211xmlChar *
1212xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1213 xmlXPathObjectPtr obj;
1214 xmlChar * ret;
1215
1216 obj = valuePop(ctxt);
1217 if (obj == NULL) {
1218 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1219 return(NULL);
1220 }
William M. Brack08171912003-12-29 02:52:11 +00001221 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001222 /* TODO: needs refactoring somewhere else */
1223 if (obj->stringval == ret)
1224 obj->stringval = NULL;
1225 xmlXPathFreeObject(obj);
1226 return(ret);
1227}
1228
1229/**
1230 * xmlXPathPopNodeSet:
1231 * @ctxt: an XPath parser context
1232 *
1233 * Pops a node-set from the stack, handling conversion if needed.
1234 * Check error with #xmlXPathCheckError.
1235 *
1236 * Returns the node-set
1237 */
1238xmlNodeSetPtr
1239xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1240 xmlXPathObjectPtr obj;
1241 xmlNodeSetPtr ret;
1242
1243 if (ctxt->value == NULL) {
1244 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1245 return(NULL);
1246 }
1247 if (!xmlXPathStackIsNodeSet(ctxt)) {
1248 xmlXPathSetTypeError(ctxt);
1249 return(NULL);
1250 }
1251 obj = valuePop(ctxt);
1252 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00001253#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00001254 /* to fix memory leak of not clearing obj->user */
1255 if (obj->boolval && obj->user != NULL)
1256 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00001257#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001258 xmlXPathFreeNodeSetList(obj);
1259 return(ret);
1260}
1261
1262/**
1263 * xmlXPathPopExternal:
1264 * @ctxt: an XPath parser context
1265 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001266 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001267 * Check error with #xmlXPathCheckError.
1268 *
1269 * Returns the object
1270 */
1271void *
1272xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1273 xmlXPathObjectPtr obj;
1274 void * ret;
1275
Daniel Veillarda82b1822004-11-08 16:24:57 +00001276 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001277 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1278 return(NULL);
1279 }
1280 if (ctxt->value->type != XPATH_USERS) {
1281 xmlXPathSetTypeError(ctxt);
1282 return(NULL);
1283 }
1284 obj = valuePop(ctxt);
1285 ret = obj->user;
1286 xmlXPathFreeObject(obj);
1287 return(ret);
1288}
1289
Owen Taylor3473f882001-02-23 17:55:21 +00001290/*
1291 * Macros for accessing the content. Those should be used only by the parser,
1292 * and not exported.
1293 *
1294 * Dirty macros, i.e. one need to make assumption on the context to use them
1295 *
1296 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1297 * CUR returns the current xmlChar value, i.e. a 8 bit value
1298 * in ISO-Latin or UTF-8.
1299 * This should be used internally by the parser
1300 * only to compare to ASCII values otherwise it would break when
1301 * running with UTF-8 encoding.
1302 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1303 * to compare on ASCII based substring.
1304 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1305 * strings within the parser.
1306 * CURRENT Returns the current char value, with the full decoding of
1307 * UTF-8 if we are using this mode. It returns an int.
1308 * NEXT Skip to the next character, this does the proper decoding
1309 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1310 * It returns the pointer to the current xmlChar.
1311 */
1312
1313#define CUR (*ctxt->cur)
1314#define SKIP(val) ctxt->cur += (val)
1315#define NXT(val) ctxt->cur[(val)]
1316#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001317#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1318
1319#define COPY_BUF(l,b,i,v) \
1320 if (l == 1) b[i++] = (xmlChar) v; \
1321 else i += xmlCopyChar(l,&b[i],v)
1322
1323#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001324
1325#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001326 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001327
1328#define CURRENT (*ctxt->cur)
1329#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1330
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001331
1332#ifndef DBL_DIG
1333#define DBL_DIG 16
1334#endif
1335#ifndef DBL_EPSILON
1336#define DBL_EPSILON 1E-9
1337#endif
1338
1339#define UPPER_DOUBLE 1E9
1340#define LOWER_DOUBLE 1E-5
1341
1342#define INTEGER_DIGITS DBL_DIG
1343#define FRACTION_DIGITS (DBL_DIG + 1)
1344#define EXPONENT_DIGITS (3 + 2)
1345
1346/**
1347 * xmlXPathFormatNumber:
1348 * @number: number to format
1349 * @buffer: output buffer
1350 * @buffersize: size of output buffer
1351 *
1352 * Convert the number into a string representation.
1353 */
1354static void
1355xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1356{
Daniel Veillardcda96922001-08-21 10:56:31 +00001357 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001358 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001359 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001360 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001361 break;
1362 case -1:
1363 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001364 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001365 break;
1366 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001367 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001368 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001369 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001370 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001371 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001372 } else if (number == ((int) number)) {
1373 char work[30];
1374 char *ptr, *cur;
1375 int res, value = (int) number;
1376
1377 ptr = &buffer[0];
1378 if (value < 0) {
1379 *ptr++ = '-';
1380 value = -value;
1381 }
1382 if (value == 0) {
1383 *ptr++ = '0';
1384 } else {
1385 cur = &work[0];
1386 while (value != 0) {
1387 res = value % 10;
1388 value = value / 10;
1389 *cur++ = '0' + res;
1390 }
1391 cur--;
1392 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1393 *ptr++ = *cur--;
1394 }
1395 }
1396 if (ptr - buffer < buffersize) {
1397 *ptr = 0;
1398 } else if (buffersize > 0) {
1399 ptr--;
1400 *ptr = 0;
1401 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001402 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001403 /* 3 is sign, decimal point, and terminating zero */
1404 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1405 int integer_place, fraction_place;
1406 char *ptr;
1407 char *after_fraction;
1408 double absolute_value;
1409 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001410
Bjorn Reese70a9da52001-04-21 16:57:29 +00001411 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001412
Bjorn Reese70a9da52001-04-21 16:57:29 +00001413 /*
1414 * First choose format - scientific or regular floating point.
1415 * In either case, result is in work, and after_fraction points
1416 * just past the fractional part.
1417 */
1418 if ( ((absolute_value > UPPER_DOUBLE) ||
1419 (absolute_value < LOWER_DOUBLE)) &&
1420 (absolute_value != 0.0) ) {
1421 /* Use scientific notation */
1422 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1423 fraction_place = DBL_DIG - 1;
1424 snprintf(work, sizeof(work),"%*.*e",
1425 integer_place, fraction_place, number);
1426 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001427 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001428 else {
1429 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001430 if (absolute_value > 0.0)
1431 integer_place = 1 + (int)log10(absolute_value);
1432 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001433 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001434 fraction_place = (integer_place > 0)
1435 ? DBL_DIG - integer_place
1436 : DBL_DIG;
1437 size = snprintf(work, sizeof(work), "%0.*f",
1438 fraction_place, number);
1439 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001440 }
1441
Bjorn Reese70a9da52001-04-21 16:57:29 +00001442 /* Remove fractional trailing zeroes */
1443 ptr = after_fraction;
1444 while (*(--ptr) == '0')
1445 ;
1446 if (*ptr != '.')
1447 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001448 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001449
1450 /* Finally copy result back to caller */
1451 size = strlen(work) + 1;
1452 if (size > buffersize) {
1453 work[buffersize - 1] = 0;
1454 size = buffersize;
1455 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001456 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001457 }
1458 break;
1459 }
1460}
1461
Owen Taylor3473f882001-02-23 17:55:21 +00001462
1463/************************************************************************
1464 * *
1465 * Routines to handle NodeSets *
1466 * *
1467 ************************************************************************/
1468
1469/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001470 * xmlXPathOrderDocElems:
1471 * @doc: an input document
1472 *
1473 * Call this routine to speed up XPath computation on static documents.
1474 * This stamps all the element nodes with the document order
1475 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00001476 * field, the value stored is actually - the node number (starting at -1)
1477 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001478 *
William M. Brack08171912003-12-29 02:52:11 +00001479 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001480 * of error.
1481 */
1482long
1483xmlXPathOrderDocElems(xmlDocPtr doc) {
1484 long count = 0;
1485 xmlNodePtr cur;
1486
1487 if (doc == NULL)
1488 return(-1);
1489 cur = doc->children;
1490 while (cur != NULL) {
1491 if (cur->type == XML_ELEMENT_NODE) {
1492 cur->content = (void *) (-(++count));
1493 if (cur->children != NULL) {
1494 cur = cur->children;
1495 continue;
1496 }
1497 }
1498 if (cur->next != NULL) {
1499 cur = cur->next;
1500 continue;
1501 }
1502 do {
1503 cur = cur->parent;
1504 if (cur == NULL)
1505 break;
1506 if (cur == (xmlNodePtr) doc) {
1507 cur = NULL;
1508 break;
1509 }
1510 if (cur->next != NULL) {
1511 cur = cur->next;
1512 break;
1513 }
1514 } while (cur != NULL);
1515 }
1516 return(count);
1517}
1518
1519/**
Owen Taylor3473f882001-02-23 17:55:21 +00001520 * xmlXPathCmpNodes:
1521 * @node1: the first node
1522 * @node2: the second node
1523 *
1524 * Compare two nodes w.r.t document order
1525 *
1526 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00001527 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001528 */
1529int
1530xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1531 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001532 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001533 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001534 xmlNodePtr cur, root;
1535
1536 if ((node1 == NULL) || (node2 == NULL))
1537 return(-2);
1538 /*
1539 * a couple of optimizations which will avoid computations in most cases
1540 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001541 if (node1->type == XML_ATTRIBUTE_NODE) {
1542 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001543 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001544 node1 = node1->parent;
1545 }
1546 if (node2->type == XML_ATTRIBUTE_NODE) {
1547 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001548 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001549 node2 = node2->parent;
1550 }
1551 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001552 if (attr1 == attr2) {
1553 /* not required, but we keep attributes in order */
1554 if (attr1 != 0) {
1555 cur = attrNode2->prev;
1556 while (cur != NULL) {
1557 if (cur == attrNode1)
1558 return (1);
1559 cur = cur->prev;
1560 }
1561 return (-1);
1562 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001563 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001564 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001565 if (attr2 == 1)
1566 return(1);
1567 return(-1);
1568 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001569 if ((node1->type == XML_NAMESPACE_DECL) ||
1570 (node2->type == XML_NAMESPACE_DECL))
1571 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001572 if (node1 == node2->prev)
1573 return(1);
1574 if (node1 == node2->next)
1575 return(-1);
1576
1577 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001578 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001579 */
1580 if ((node1->type == XML_ELEMENT_NODE) &&
1581 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001582 (0 > (long) node1->content) &&
1583 (0 > (long) node2->content) &&
1584 (node1->doc == node2->doc)) {
1585 long l1, l2;
1586
1587 l1 = -((long) node1->content);
1588 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001589 if (l1 < l2)
1590 return(1);
1591 if (l1 > l2)
1592 return(-1);
1593 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001594
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001595 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001596 * compute depth to root
1597 */
1598 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1599 if (cur == node1)
1600 return(1);
1601 depth2++;
1602 }
1603 root = cur;
1604 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1605 if (cur == node2)
1606 return(-1);
1607 depth1++;
1608 }
1609 /*
1610 * Distinct document (or distinct entities :-( ) case.
1611 */
1612 if (root != cur) {
1613 return(-2);
1614 }
1615 /*
1616 * get the nearest common ancestor.
1617 */
1618 while (depth1 > depth2) {
1619 depth1--;
1620 node1 = node1->parent;
1621 }
1622 while (depth2 > depth1) {
1623 depth2--;
1624 node2 = node2->parent;
1625 }
1626 while (node1->parent != node2->parent) {
1627 node1 = node1->parent;
1628 node2 = node2->parent;
1629 /* should not happen but just in case ... */
1630 if ((node1 == NULL) || (node2 == NULL))
1631 return(-2);
1632 }
1633 /*
1634 * Find who's first.
1635 */
Daniel Veillardf49be472004-02-17 11:48:18 +00001636 if (node1 == node2->prev)
1637 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001638 if (node1 == node2->next)
1639 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00001640 /*
1641 * Speedup using document order if availble.
1642 */
1643 if ((node1->type == XML_ELEMENT_NODE) &&
1644 (node2->type == XML_ELEMENT_NODE) &&
1645 (0 > (long) node1->content) &&
1646 (0 > (long) node2->content) &&
1647 (node1->doc == node2->doc)) {
1648 long l1, l2;
1649
1650 l1 = -((long) node1->content);
1651 l2 = -((long) node2->content);
1652 if (l1 < l2)
1653 return(1);
1654 if (l1 > l2)
1655 return(-1);
1656 }
1657
Owen Taylor3473f882001-02-23 17:55:21 +00001658 for (cur = node1->next;cur != NULL;cur = cur->next)
1659 if (cur == node2)
1660 return(1);
1661 return(-1); /* assume there is no sibling list corruption */
1662}
1663
1664/**
1665 * xmlXPathNodeSetSort:
1666 * @set: the node set
1667 *
1668 * Sort the node set in document order
1669 */
1670void
1671xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001672 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001673 xmlNodePtr tmp;
1674
1675 if (set == NULL)
1676 return;
1677
1678 /* Use Shell's sort to sort the node-set */
1679 len = set->nodeNr;
1680 for (incr = len / 2; incr > 0; incr /= 2) {
1681 for (i = incr; i < len; i++) {
1682 j = i - incr;
1683 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001684 if (xmlXPathCmpNodes(set->nodeTab[j],
1685 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001686 tmp = set->nodeTab[j];
1687 set->nodeTab[j] = set->nodeTab[j + incr];
1688 set->nodeTab[j + incr] = tmp;
1689 j -= incr;
1690 } else
1691 break;
1692 }
1693 }
1694 }
1695}
1696
1697#define XML_NODESET_DEFAULT 10
1698/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001699 * xmlXPathNodeSetDupNs:
1700 * @node: the parent node of the namespace XPath node
1701 * @ns: the libxml namespace declaration node.
1702 *
1703 * Namespace node in libxml don't match the XPath semantic. In a node set
1704 * the namespace nodes are duplicated and the next pointer is set to the
1705 * parent node in the XPath semantic.
1706 *
1707 * Returns the newly created object.
1708 */
1709static xmlNodePtr
1710xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1711 xmlNsPtr cur;
1712
1713 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1714 return(NULL);
1715 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1716 return((xmlNodePtr) ns);
1717
1718 /*
1719 * Allocate a new Namespace and fill the fields.
1720 */
1721 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1722 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001723 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001724 return(NULL);
1725 }
1726 memset(cur, 0, sizeof(xmlNs));
1727 cur->type = XML_NAMESPACE_DECL;
1728 if (ns->href != NULL)
1729 cur->href = xmlStrdup(ns->href);
1730 if (ns->prefix != NULL)
1731 cur->prefix = xmlStrdup(ns->prefix);
1732 cur->next = (xmlNsPtr) node;
1733 return((xmlNodePtr) cur);
1734}
1735
1736/**
1737 * xmlXPathNodeSetFreeNs:
1738 * @ns: the XPath namespace node found in a nodeset.
1739 *
William M. Brack08171912003-12-29 02:52:11 +00001740 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001741 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00001742 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001743 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001744void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001745xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1746 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1747 return;
1748
1749 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1750 if (ns->href != NULL)
1751 xmlFree((xmlChar *)ns->href);
1752 if (ns->prefix != NULL)
1753 xmlFree((xmlChar *)ns->prefix);
1754 xmlFree(ns);
1755 }
1756}
1757
1758/**
Owen Taylor3473f882001-02-23 17:55:21 +00001759 * xmlXPathNodeSetCreate:
1760 * @val: an initial xmlNodePtr, or NULL
1761 *
1762 * Create a new xmlNodeSetPtr of type double and of value @val
1763 *
1764 * Returns the newly created object.
1765 */
1766xmlNodeSetPtr
1767xmlXPathNodeSetCreate(xmlNodePtr val) {
1768 xmlNodeSetPtr ret;
1769
1770 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1771 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001772 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001773 return(NULL);
1774 }
1775 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1776 if (val != NULL) {
1777 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1778 sizeof(xmlNodePtr));
1779 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001780 xmlXPathErrMemory(NULL, "creating nodeset\n");
1781 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001782 return(NULL);
1783 }
1784 memset(ret->nodeTab, 0 ,
1785 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1786 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001787 if (val->type == XML_NAMESPACE_DECL) {
1788 xmlNsPtr ns = (xmlNsPtr) val;
1789
1790 ret->nodeTab[ret->nodeNr++] =
1791 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1792 } else
1793 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001794 }
1795 return(ret);
1796}
1797
1798/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001799 * xmlXPathNodeSetContains:
1800 * @cur: the node-set
1801 * @val: the node
1802 *
1803 * checks whether @cur contains @val
1804 *
1805 * Returns true (1) if @cur contains @val, false (0) otherwise
1806 */
1807int
1808xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1809 int i;
1810
Daniel Veillarda82b1822004-11-08 16:24:57 +00001811 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001812 if (val->type == XML_NAMESPACE_DECL) {
1813 for (i = 0; i < cur->nodeNr; i++) {
1814 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1815 xmlNsPtr ns1, ns2;
1816
1817 ns1 = (xmlNsPtr) val;
1818 ns2 = (xmlNsPtr) cur->nodeTab[i];
1819 if (ns1 == ns2)
1820 return(1);
1821 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1822 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1823 return(1);
1824 }
1825 }
1826 } else {
1827 for (i = 0; i < cur->nodeNr; i++) {
1828 if (cur->nodeTab[i] == val)
1829 return(1);
1830 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001831 }
1832 return(0);
1833}
1834
1835/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001836 * xmlXPathNodeSetAddNs:
1837 * @cur: the initial node set
1838 * @node: the hosting node
1839 * @ns: a the namespace node
1840 *
1841 * add a new namespace node to an existing NodeSet
1842 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001843void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001844xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1845 int i;
1846
Daniel Veillarda82b1822004-11-08 16:24:57 +00001847
1848 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
1849 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001850 (node->type != XML_ELEMENT_NODE))
1851 return;
1852
William M. Brack08171912003-12-29 02:52:11 +00001853 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001854 /*
William M. Brack08171912003-12-29 02:52:11 +00001855 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001856 */
1857 for (i = 0;i < cur->nodeNr;i++) {
1858 if ((cur->nodeTab[i] != NULL) &&
1859 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001860 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001861 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1862 return;
1863 }
1864
1865 /*
1866 * grow the nodeTab if needed
1867 */
1868 if (cur->nodeMax == 0) {
1869 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1870 sizeof(xmlNodePtr));
1871 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001872 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001873 return;
1874 }
1875 memset(cur->nodeTab, 0 ,
1876 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1877 cur->nodeMax = XML_NODESET_DEFAULT;
1878 } else if (cur->nodeNr == cur->nodeMax) {
1879 xmlNodePtr *temp;
1880
1881 cur->nodeMax *= 2;
1882 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1883 sizeof(xmlNodePtr));
1884 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001885 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001886 return;
1887 }
1888 cur->nodeTab = temp;
1889 }
1890 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1891}
1892
1893/**
Owen Taylor3473f882001-02-23 17:55:21 +00001894 * xmlXPathNodeSetAdd:
1895 * @cur: the initial node set
1896 * @val: a new xmlNodePtr
1897 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001898 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001899 */
1900void
1901xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1902 int i;
1903
Daniel Veillarda82b1822004-11-08 16:24:57 +00001904 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001905
Daniel Veillardef0b4502003-03-24 13:57:34 +00001906#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001907 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1908 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001909#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001910
William M. Brack08171912003-12-29 02:52:11 +00001911 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001912 /*
William M. Brack08171912003-12-29 02:52:11 +00001913 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00001914 */
1915 for (i = 0;i < cur->nodeNr;i++)
1916 if (cur->nodeTab[i] == val) return;
1917
1918 /*
1919 * grow the nodeTab if needed
1920 */
1921 if (cur->nodeMax == 0) {
1922 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1923 sizeof(xmlNodePtr));
1924 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001925 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001926 return;
1927 }
1928 memset(cur->nodeTab, 0 ,
1929 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1930 cur->nodeMax = XML_NODESET_DEFAULT;
1931 } else if (cur->nodeNr == cur->nodeMax) {
1932 xmlNodePtr *temp;
1933
1934 cur->nodeMax *= 2;
1935 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1936 sizeof(xmlNodePtr));
1937 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001938 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001939 return;
1940 }
1941 cur->nodeTab = temp;
1942 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001943 if (val->type == XML_NAMESPACE_DECL) {
1944 xmlNsPtr ns = (xmlNsPtr) val;
1945
1946 cur->nodeTab[cur->nodeNr++] =
1947 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1948 } else
1949 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001950}
1951
1952/**
1953 * xmlXPathNodeSetAddUnique:
1954 * @cur: the initial node set
1955 * @val: a new xmlNodePtr
1956 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001957 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001958 * when we are sure the node is not already in the set.
1959 */
1960void
1961xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00001962 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001963
Daniel Veillardef0b4502003-03-24 13:57:34 +00001964#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001965 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1966 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001967#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001968
William M. Brack08171912003-12-29 02:52:11 +00001969 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001970 /*
1971 * grow the nodeTab if needed
1972 */
1973 if (cur->nodeMax == 0) {
1974 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1975 sizeof(xmlNodePtr));
1976 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001977 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001978 return;
1979 }
1980 memset(cur->nodeTab, 0 ,
1981 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1982 cur->nodeMax = XML_NODESET_DEFAULT;
1983 } else if (cur->nodeNr == cur->nodeMax) {
1984 xmlNodePtr *temp;
1985
1986 cur->nodeMax *= 2;
1987 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1988 sizeof(xmlNodePtr));
1989 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001990 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001991 return;
1992 }
1993 cur->nodeTab = temp;
1994 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001995 if (val->type == XML_NAMESPACE_DECL) {
1996 xmlNsPtr ns = (xmlNsPtr) val;
1997
1998 cur->nodeTab[cur->nodeNr++] =
1999 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2000 } else
2001 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00002002}
2003
2004/**
2005 * xmlXPathNodeSetMerge:
2006 * @val1: the first NodeSet or NULL
2007 * @val2: the second NodeSet
2008 *
2009 * Merges two nodesets, all nodes from @val2 are added to @val1
2010 * if @val1 is NULL, a new set is created and copied from @val2
2011 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002012 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002013 */
2014xmlNodeSetPtr
2015xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002016 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00002017
2018 if (val2 == NULL) return(val1);
2019 if (val1 == NULL) {
2020 val1 = xmlXPathNodeSetCreate(NULL);
2021 }
2022
William M. Brack08171912003-12-29 02:52:11 +00002023 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002024 initNr = val1->nodeNr;
2025
2026 for (i = 0;i < val2->nodeNr;i++) {
2027 /*
William M. Brack08171912003-12-29 02:52:11 +00002028 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00002029 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002030 skip = 0;
2031 for (j = 0; j < initNr; j++) {
2032 if (val1->nodeTab[j] == val2->nodeTab[i]) {
2033 skip = 1;
2034 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002035 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
2036 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
2037 xmlNsPtr ns1, ns2;
2038 ns1 = (xmlNsPtr) val1->nodeTab[j];
2039 ns2 = (xmlNsPtr) val2->nodeTab[i];
2040 if ((ns1->next == ns2->next) &&
2041 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
2042 skip = 1;
2043 break;
2044 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002045 }
2046 }
2047 if (skip)
2048 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00002049
2050 /*
2051 * grow the nodeTab if needed
2052 */
2053 if (val1->nodeMax == 0) {
2054 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2055 sizeof(xmlNodePtr));
2056 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002057 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002058 return(NULL);
2059 }
2060 memset(val1->nodeTab, 0 ,
2061 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2062 val1->nodeMax = XML_NODESET_DEFAULT;
2063 } else if (val1->nodeNr == val1->nodeMax) {
2064 xmlNodePtr *temp;
2065
2066 val1->nodeMax *= 2;
2067 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2068 sizeof(xmlNodePtr));
2069 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002070 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002071 return(NULL);
2072 }
2073 val1->nodeTab = temp;
2074 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002075 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2076 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2077
2078 val1->nodeTab[val1->nodeNr++] =
2079 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2080 } else
2081 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002082 }
2083
2084 return(val1);
2085}
2086
2087/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002088 * xmlXPathNodeSetMergeUnique:
2089 * @val1: the first NodeSet or NULL
2090 * @val2: the second NodeSet
2091 *
2092 * Merges two nodesets, all nodes from @val2 are added to @val1
2093 * if @val1 is NULL, a new set is created and copied from @val2
2094 *
2095 * Returns @val1 once extended or NULL in case of error.
2096 */
2097static xmlNodeSetPtr
2098xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002099 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002100
2101 if (val2 == NULL) return(val1);
2102 if (val1 == NULL) {
2103 val1 = xmlXPathNodeSetCreate(NULL);
2104 }
2105
William M. Brack08171912003-12-29 02:52:11 +00002106 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002107
2108 for (i = 0;i < val2->nodeNr;i++) {
2109 /*
2110 * grow the nodeTab if needed
2111 */
2112 if (val1->nodeMax == 0) {
2113 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2114 sizeof(xmlNodePtr));
2115 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002116 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002117 return(NULL);
2118 }
2119 memset(val1->nodeTab, 0 ,
2120 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2121 val1->nodeMax = XML_NODESET_DEFAULT;
2122 } else if (val1->nodeNr == val1->nodeMax) {
2123 xmlNodePtr *temp;
2124
2125 val1->nodeMax *= 2;
2126 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2127 sizeof(xmlNodePtr));
2128 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002129 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002130 return(NULL);
2131 }
2132 val1->nodeTab = temp;
2133 }
2134 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2135 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2136
2137 val1->nodeTab[val1->nodeNr++] =
2138 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2139 } else
2140 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2141 }
2142
2143 return(val1);
2144}
2145
2146/**
Owen Taylor3473f882001-02-23 17:55:21 +00002147 * xmlXPathNodeSetDel:
2148 * @cur: the initial node set
2149 * @val: an xmlNodePtr
2150 *
2151 * Removes an xmlNodePtr from an existing NodeSet
2152 */
2153void
2154xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2155 int i;
2156
2157 if (cur == NULL) return;
2158 if (val == NULL) return;
2159
2160 /*
William M. Brack08171912003-12-29 02:52:11 +00002161 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002162 */
2163 for (i = 0;i < cur->nodeNr;i++)
2164 if (cur->nodeTab[i] == val) break;
2165
William M. Brack08171912003-12-29 02:52:11 +00002166 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002167#ifdef DEBUG
2168 xmlGenericError(xmlGenericErrorContext,
2169 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2170 val->name);
2171#endif
2172 return;
2173 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002174 if ((cur->nodeTab[i] != NULL) &&
2175 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2176 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002177 cur->nodeNr--;
2178 for (;i < cur->nodeNr;i++)
2179 cur->nodeTab[i] = cur->nodeTab[i + 1];
2180 cur->nodeTab[cur->nodeNr] = NULL;
2181}
2182
2183/**
2184 * xmlXPathNodeSetRemove:
2185 * @cur: the initial node set
2186 * @val: the index to remove
2187 *
2188 * Removes an entry from an existing NodeSet list.
2189 */
2190void
2191xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2192 if (cur == NULL) return;
2193 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002194 if ((cur->nodeTab[val] != NULL) &&
2195 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2196 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002197 cur->nodeNr--;
2198 for (;val < cur->nodeNr;val++)
2199 cur->nodeTab[val] = cur->nodeTab[val + 1];
2200 cur->nodeTab[cur->nodeNr] = NULL;
2201}
2202
2203/**
2204 * xmlXPathFreeNodeSet:
2205 * @obj: the xmlNodeSetPtr to free
2206 *
2207 * Free the NodeSet compound (not the actual nodes !).
2208 */
2209void
2210xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2211 if (obj == NULL) return;
2212 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002213 int i;
2214
William M. Brack08171912003-12-29 02:52:11 +00002215 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002216 for (i = 0;i < obj->nodeNr;i++)
2217 if ((obj->nodeTab[i] != NULL) &&
2218 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2219 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002220 xmlFree(obj->nodeTab);
2221 }
Owen Taylor3473f882001-02-23 17:55:21 +00002222 xmlFree(obj);
2223}
2224
2225/**
2226 * xmlXPathFreeValueTree:
2227 * @obj: the xmlNodeSetPtr to free
2228 *
2229 * Free the NodeSet compound and the actual tree, this is different
2230 * from xmlXPathFreeNodeSet()
2231 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002232static void
Owen Taylor3473f882001-02-23 17:55:21 +00002233xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2234 int i;
2235
2236 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002237
2238 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002239 for (i = 0;i < obj->nodeNr;i++) {
2240 if (obj->nodeTab[i] != NULL) {
2241 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2242 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2243 } else {
2244 xmlFreeNodeList(obj->nodeTab[i]);
2245 }
2246 }
2247 }
Owen Taylor3473f882001-02-23 17:55:21 +00002248 xmlFree(obj->nodeTab);
2249 }
Owen Taylor3473f882001-02-23 17:55:21 +00002250 xmlFree(obj);
2251}
2252
2253#if defined(DEBUG) || defined(DEBUG_STEP)
2254/**
2255 * xmlGenericErrorContextNodeSet:
2256 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002257 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002258 *
2259 * Quick display of a NodeSet
2260 */
2261void
2262xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2263 int i;
2264
2265 if (output == NULL) output = xmlGenericErrorContext;
2266 if (obj == NULL) {
2267 fprintf(output, "NodeSet == NULL !\n");
2268 return;
2269 }
2270 if (obj->nodeNr == 0) {
2271 fprintf(output, "NodeSet is empty\n");
2272 return;
2273 }
2274 if (obj->nodeTab == NULL) {
2275 fprintf(output, " nodeTab == NULL !\n");
2276 return;
2277 }
2278 for (i = 0; i < obj->nodeNr; i++) {
2279 if (obj->nodeTab[i] == NULL) {
2280 fprintf(output, " NULL !\n");
2281 return;
2282 }
2283 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2284 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2285 fprintf(output, " /");
2286 else if (obj->nodeTab[i]->name == NULL)
2287 fprintf(output, " noname!");
2288 else fprintf(output, " %s", obj->nodeTab[i]->name);
2289 }
2290 fprintf(output, "\n");
2291}
2292#endif
2293
2294/**
2295 * xmlXPathNewNodeSet:
2296 * @val: the NodePtr value
2297 *
2298 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2299 * it with the single Node @val
2300 *
2301 * Returns the newly created object.
2302 */
2303xmlXPathObjectPtr
2304xmlXPathNewNodeSet(xmlNodePtr val) {
2305 xmlXPathObjectPtr ret;
2306
2307 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2308 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002309 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002310 return(NULL);
2311 }
2312 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2313 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002314 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002315 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002316 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002317 return(ret);
2318}
2319
2320/**
2321 * xmlXPathNewValueTree:
2322 * @val: the NodePtr value
2323 *
2324 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2325 * it with the tree root @val
2326 *
2327 * Returns the newly created object.
2328 */
2329xmlXPathObjectPtr
2330xmlXPathNewValueTree(xmlNodePtr val) {
2331 xmlXPathObjectPtr ret;
2332
2333 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2334 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002335 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002336 return(NULL);
2337 }
2338 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2339 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002340 ret->boolval = 1;
2341 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002342 ret->nodesetval = xmlXPathNodeSetCreate(val);
2343 return(ret);
2344}
2345
2346/**
2347 * xmlXPathNewNodeSetList:
2348 * @val: an existing NodeSet
2349 *
2350 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2351 * it with the Nodeset @val
2352 *
2353 * Returns the newly created object.
2354 */
2355xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002356xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2357{
Owen Taylor3473f882001-02-23 17:55:21 +00002358 xmlXPathObjectPtr ret;
2359 int i;
2360
2361 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002362 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002363 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002364 ret = xmlXPathNewNodeSet(NULL);
2365 else {
2366 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2367 for (i = 1; i < val->nodeNr; ++i)
2368 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2369 }
Owen Taylor3473f882001-02-23 17:55:21 +00002370
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002371 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002372}
2373
2374/**
2375 * xmlXPathWrapNodeSet:
2376 * @val: the NodePtr value
2377 *
2378 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2379 *
2380 * Returns the newly created object.
2381 */
2382xmlXPathObjectPtr
2383xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2384 xmlXPathObjectPtr ret;
2385
2386 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2387 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002388 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002389 return(NULL);
2390 }
2391 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2392 ret->type = XPATH_NODESET;
2393 ret->nodesetval = val;
2394 return(ret);
2395}
2396
2397/**
2398 * xmlXPathFreeNodeSetList:
2399 * @obj: an existing NodeSetList object
2400 *
2401 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2402 * the list contrary to xmlXPathFreeObject().
2403 */
2404void
2405xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2406 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002407 xmlFree(obj);
2408}
2409
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002410/**
2411 * xmlXPathDifference:
2412 * @nodes1: a node-set
2413 * @nodes2: a node-set
2414 *
2415 * Implements the EXSLT - Sets difference() function:
2416 * node-set set:difference (node-set, node-set)
2417 *
2418 * Returns the difference between the two node sets, or nodes1 if
2419 * nodes2 is empty
2420 */
2421xmlNodeSetPtr
2422xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2423 xmlNodeSetPtr ret;
2424 int i, l1;
2425 xmlNodePtr cur;
2426
2427 if (xmlXPathNodeSetIsEmpty(nodes2))
2428 return(nodes1);
2429
2430 ret = xmlXPathNodeSetCreate(NULL);
2431 if (xmlXPathNodeSetIsEmpty(nodes1))
2432 return(ret);
2433
2434 l1 = xmlXPathNodeSetGetLength(nodes1);
2435
2436 for (i = 0; i < l1; i++) {
2437 cur = xmlXPathNodeSetItem(nodes1, i);
2438 if (!xmlXPathNodeSetContains(nodes2, cur))
2439 xmlXPathNodeSetAddUnique(ret, cur);
2440 }
2441 return(ret);
2442}
2443
2444/**
2445 * xmlXPathIntersection:
2446 * @nodes1: a node-set
2447 * @nodes2: a node-set
2448 *
2449 * Implements the EXSLT - Sets intersection() function:
2450 * node-set set:intersection (node-set, node-set)
2451 *
2452 * Returns a node set comprising the nodes that are within both the
2453 * node sets passed as arguments
2454 */
2455xmlNodeSetPtr
2456xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2457 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2458 int i, l1;
2459 xmlNodePtr cur;
2460
2461 if (xmlXPathNodeSetIsEmpty(nodes1))
2462 return(ret);
2463 if (xmlXPathNodeSetIsEmpty(nodes2))
2464 return(ret);
2465
2466 l1 = xmlXPathNodeSetGetLength(nodes1);
2467
2468 for (i = 0; i < l1; i++) {
2469 cur = xmlXPathNodeSetItem(nodes1, i);
2470 if (xmlXPathNodeSetContains(nodes2, cur))
2471 xmlXPathNodeSetAddUnique(ret, cur);
2472 }
2473 return(ret);
2474}
2475
2476/**
2477 * xmlXPathDistinctSorted:
2478 * @nodes: a node-set, sorted by document order
2479 *
2480 * Implements the EXSLT - Sets distinct() function:
2481 * node-set set:distinct (node-set)
2482 *
2483 * Returns a subset of the nodes contained in @nodes, or @nodes if
2484 * it is empty
2485 */
2486xmlNodeSetPtr
2487xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2488 xmlNodeSetPtr ret;
2489 xmlHashTablePtr hash;
2490 int i, l;
2491 xmlChar * strval;
2492 xmlNodePtr cur;
2493
2494 if (xmlXPathNodeSetIsEmpty(nodes))
2495 return(nodes);
2496
2497 ret = xmlXPathNodeSetCreate(NULL);
2498 l = xmlXPathNodeSetGetLength(nodes);
2499 hash = xmlHashCreate (l);
2500 for (i = 0; i < l; i++) {
2501 cur = xmlXPathNodeSetItem(nodes, i);
2502 strval = xmlXPathCastNodeToString(cur);
2503 if (xmlHashLookup(hash, strval) == NULL) {
2504 xmlHashAddEntry(hash, strval, strval);
2505 xmlXPathNodeSetAddUnique(ret, cur);
2506 } else {
2507 xmlFree(strval);
2508 }
2509 }
2510 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2511 return(ret);
2512}
2513
2514/**
2515 * xmlXPathDistinct:
2516 * @nodes: a node-set
2517 *
2518 * Implements the EXSLT - Sets distinct() function:
2519 * node-set set:distinct (node-set)
2520 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2521 * is called with the sorted node-set
2522 *
2523 * Returns a subset of the nodes contained in @nodes, or @nodes if
2524 * it is empty
2525 */
2526xmlNodeSetPtr
2527xmlXPathDistinct (xmlNodeSetPtr nodes) {
2528 if (xmlXPathNodeSetIsEmpty(nodes))
2529 return(nodes);
2530
2531 xmlXPathNodeSetSort(nodes);
2532 return(xmlXPathDistinctSorted(nodes));
2533}
2534
2535/**
2536 * xmlXPathHasSameNodes:
2537 * @nodes1: a node-set
2538 * @nodes2: a node-set
2539 *
2540 * Implements the EXSLT - Sets has-same-nodes function:
2541 * boolean set:has-same-node(node-set, node-set)
2542 *
2543 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2544 * otherwise
2545 */
2546int
2547xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2548 int i, l;
2549 xmlNodePtr cur;
2550
2551 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2552 xmlXPathNodeSetIsEmpty(nodes2))
2553 return(0);
2554
2555 l = xmlXPathNodeSetGetLength(nodes1);
2556 for (i = 0; i < l; i++) {
2557 cur = xmlXPathNodeSetItem(nodes1, i);
2558 if (xmlXPathNodeSetContains(nodes2, cur))
2559 return(1);
2560 }
2561 return(0);
2562}
2563
2564/**
2565 * xmlXPathNodeLeadingSorted:
2566 * @nodes: a node-set, sorted by document order
2567 * @node: a node
2568 *
2569 * Implements the EXSLT - Sets leading() function:
2570 * node-set set:leading (node-set, node-set)
2571 *
2572 * Returns the nodes in @nodes that precede @node in document order,
2573 * @nodes if @node is NULL or an empty node-set if @nodes
2574 * doesn't contain @node
2575 */
2576xmlNodeSetPtr
2577xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2578 int i, l;
2579 xmlNodePtr cur;
2580 xmlNodeSetPtr ret;
2581
2582 if (node == NULL)
2583 return(nodes);
2584
2585 ret = xmlXPathNodeSetCreate(NULL);
2586 if (xmlXPathNodeSetIsEmpty(nodes) ||
2587 (!xmlXPathNodeSetContains(nodes, node)))
2588 return(ret);
2589
2590 l = xmlXPathNodeSetGetLength(nodes);
2591 for (i = 0; i < l; i++) {
2592 cur = xmlXPathNodeSetItem(nodes, i);
2593 if (cur == node)
2594 break;
2595 xmlXPathNodeSetAddUnique(ret, cur);
2596 }
2597 return(ret);
2598}
2599
2600/**
2601 * xmlXPathNodeLeading:
2602 * @nodes: a node-set
2603 * @node: a node
2604 *
2605 * Implements the EXSLT - Sets leading() function:
2606 * node-set set:leading (node-set, node-set)
2607 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2608 * is called.
2609 *
2610 * Returns the nodes in @nodes that precede @node in document order,
2611 * @nodes if @node is NULL or an empty node-set if @nodes
2612 * doesn't contain @node
2613 */
2614xmlNodeSetPtr
2615xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2616 xmlXPathNodeSetSort(nodes);
2617 return(xmlXPathNodeLeadingSorted(nodes, node));
2618}
2619
2620/**
2621 * xmlXPathLeadingSorted:
2622 * @nodes1: a node-set, sorted by document order
2623 * @nodes2: a node-set, sorted by document order
2624 *
2625 * Implements the EXSLT - Sets leading() function:
2626 * node-set set:leading (node-set, node-set)
2627 *
2628 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2629 * in document order, @nodes1 if @nodes2 is NULL or empty or
2630 * an empty node-set if @nodes1 doesn't contain @nodes2
2631 */
2632xmlNodeSetPtr
2633xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2634 if (xmlXPathNodeSetIsEmpty(nodes2))
2635 return(nodes1);
2636 return(xmlXPathNodeLeadingSorted(nodes1,
2637 xmlXPathNodeSetItem(nodes2, 1)));
2638}
2639
2640/**
2641 * xmlXPathLeading:
2642 * @nodes1: a node-set
2643 * @nodes2: a node-set
2644 *
2645 * Implements the EXSLT - Sets leading() function:
2646 * node-set set:leading (node-set, node-set)
2647 * @nodes1 and @nodes2 are sorted by document order, then
2648 * #exslSetsLeadingSorted is called.
2649 *
2650 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2651 * in document order, @nodes1 if @nodes2 is NULL or empty or
2652 * an empty node-set if @nodes1 doesn't contain @nodes2
2653 */
2654xmlNodeSetPtr
2655xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2656 if (xmlXPathNodeSetIsEmpty(nodes2))
2657 return(nodes1);
2658 if (xmlXPathNodeSetIsEmpty(nodes1))
2659 return(xmlXPathNodeSetCreate(NULL));
2660 xmlXPathNodeSetSort(nodes1);
2661 xmlXPathNodeSetSort(nodes2);
2662 return(xmlXPathNodeLeadingSorted(nodes1,
2663 xmlXPathNodeSetItem(nodes2, 1)));
2664}
2665
2666/**
2667 * xmlXPathNodeTrailingSorted:
2668 * @nodes: a node-set, sorted by document order
2669 * @node: a node
2670 *
2671 * Implements the EXSLT - Sets trailing() function:
2672 * node-set set:trailing (node-set, node-set)
2673 *
2674 * Returns the nodes in @nodes that follow @node in document order,
2675 * @nodes if @node is NULL or an empty node-set if @nodes
2676 * doesn't contain @node
2677 */
2678xmlNodeSetPtr
2679xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2680 int i, l;
2681 xmlNodePtr cur;
2682 xmlNodeSetPtr ret;
2683
2684 if (node == NULL)
2685 return(nodes);
2686
2687 ret = xmlXPathNodeSetCreate(NULL);
2688 if (xmlXPathNodeSetIsEmpty(nodes) ||
2689 (!xmlXPathNodeSetContains(nodes, node)))
2690 return(ret);
2691
2692 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002693 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002694 cur = xmlXPathNodeSetItem(nodes, i);
2695 if (cur == node)
2696 break;
2697 xmlXPathNodeSetAddUnique(ret, cur);
2698 }
2699 return(ret);
2700}
2701
2702/**
2703 * xmlXPathNodeTrailing:
2704 * @nodes: a node-set
2705 * @node: a node
2706 *
2707 * Implements the EXSLT - Sets trailing() function:
2708 * node-set set:trailing (node-set, node-set)
2709 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2710 * is called.
2711 *
2712 * Returns the nodes in @nodes that follow @node in document order,
2713 * @nodes if @node is NULL or an empty node-set if @nodes
2714 * doesn't contain @node
2715 */
2716xmlNodeSetPtr
2717xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2718 xmlXPathNodeSetSort(nodes);
2719 return(xmlXPathNodeTrailingSorted(nodes, node));
2720}
2721
2722/**
2723 * xmlXPathTrailingSorted:
2724 * @nodes1: a node-set, sorted by document order
2725 * @nodes2: a node-set, sorted by document order
2726 *
2727 * Implements the EXSLT - Sets trailing() function:
2728 * node-set set:trailing (node-set, node-set)
2729 *
2730 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2731 * in document order, @nodes1 if @nodes2 is NULL or empty or
2732 * an empty node-set if @nodes1 doesn't contain @nodes2
2733 */
2734xmlNodeSetPtr
2735xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2736 if (xmlXPathNodeSetIsEmpty(nodes2))
2737 return(nodes1);
2738 return(xmlXPathNodeTrailingSorted(nodes1,
2739 xmlXPathNodeSetItem(nodes2, 0)));
2740}
2741
2742/**
2743 * xmlXPathTrailing:
2744 * @nodes1: a node-set
2745 * @nodes2: a node-set
2746 *
2747 * Implements the EXSLT - Sets trailing() function:
2748 * node-set set:trailing (node-set, node-set)
2749 * @nodes1 and @nodes2 are sorted by document order, then
2750 * #xmlXPathTrailingSorted is called.
2751 *
2752 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2753 * in document order, @nodes1 if @nodes2 is NULL or empty or
2754 * an empty node-set if @nodes1 doesn't contain @nodes2
2755 */
2756xmlNodeSetPtr
2757xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2758 if (xmlXPathNodeSetIsEmpty(nodes2))
2759 return(nodes1);
2760 if (xmlXPathNodeSetIsEmpty(nodes1))
2761 return(xmlXPathNodeSetCreate(NULL));
2762 xmlXPathNodeSetSort(nodes1);
2763 xmlXPathNodeSetSort(nodes2);
2764 return(xmlXPathNodeTrailingSorted(nodes1,
2765 xmlXPathNodeSetItem(nodes2, 0)));
2766}
2767
Owen Taylor3473f882001-02-23 17:55:21 +00002768/************************************************************************
2769 * *
2770 * Routines to handle extra functions *
2771 * *
2772 ************************************************************************/
2773
2774/**
2775 * xmlXPathRegisterFunc:
2776 * @ctxt: the XPath context
2777 * @name: the function name
2778 * @f: the function implementation or NULL
2779 *
2780 * Register a new function. If @f is NULL it unregisters the function
2781 *
2782 * Returns 0 in case of success, -1 in case of error
2783 */
2784int
2785xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2786 xmlXPathFunction f) {
2787 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2788}
2789
2790/**
2791 * xmlXPathRegisterFuncNS:
2792 * @ctxt: the XPath context
2793 * @name: the function name
2794 * @ns_uri: the function namespace URI
2795 * @f: the function implementation or NULL
2796 *
2797 * Register a new function. If @f is NULL it unregisters the function
2798 *
2799 * Returns 0 in case of success, -1 in case of error
2800 */
2801int
2802xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2803 const xmlChar *ns_uri, xmlXPathFunction f) {
2804 if (ctxt == NULL)
2805 return(-1);
2806 if (name == NULL)
2807 return(-1);
2808
2809 if (ctxt->funcHash == NULL)
2810 ctxt->funcHash = xmlHashCreate(0);
2811 if (ctxt->funcHash == NULL)
2812 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002813 if (f == NULL)
2814 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
Owen Taylor3473f882001-02-23 17:55:21 +00002815 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2816}
2817
2818/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002819 * xmlXPathRegisterFuncLookup:
2820 * @ctxt: the XPath context
2821 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002822 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002823 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002824 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002825 */
2826void
2827xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2828 xmlXPathFuncLookupFunc f,
2829 void *funcCtxt) {
2830 if (ctxt == NULL)
2831 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002832 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002833 ctxt->funcLookupData = funcCtxt;
2834}
2835
2836/**
Owen Taylor3473f882001-02-23 17:55:21 +00002837 * xmlXPathFunctionLookup:
2838 * @ctxt: the XPath context
2839 * @name: the function name
2840 *
2841 * Search in the Function array of the context for the given
2842 * function.
2843 *
2844 * Returns the xmlXPathFunction or NULL if not found
2845 */
2846xmlXPathFunction
2847xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002848 if (ctxt == NULL)
2849 return (NULL);
2850
2851 if (ctxt->funcLookupFunc != NULL) {
2852 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002853 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002854
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002855 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002856 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002857 if (ret != NULL)
2858 return(ret);
2859 }
Owen Taylor3473f882001-02-23 17:55:21 +00002860 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2861}
2862
2863/**
2864 * xmlXPathFunctionLookupNS:
2865 * @ctxt: the XPath context
2866 * @name: the function name
2867 * @ns_uri: the function namespace URI
2868 *
2869 * Search in the Function array of the context for the given
2870 * function.
2871 *
2872 * Returns the xmlXPathFunction or NULL if not found
2873 */
2874xmlXPathFunction
2875xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2876 const xmlChar *ns_uri) {
2877 if (ctxt == NULL)
2878 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002879 if (name == NULL)
2880 return(NULL);
2881
Thomas Broyerba4ad322001-07-26 16:55:21 +00002882 if (ctxt->funcLookupFunc != NULL) {
2883 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002884 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002885
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002886 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002887 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002888 if (ret != NULL)
2889 return(ret);
2890 }
2891
2892 if (ctxt->funcHash == NULL)
2893 return(NULL);
2894
Owen Taylor3473f882001-02-23 17:55:21 +00002895 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2896}
2897
2898/**
2899 * xmlXPathRegisteredFuncsCleanup:
2900 * @ctxt: the XPath context
2901 *
2902 * Cleanup the XPath context data associated to registered functions
2903 */
2904void
2905xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2906 if (ctxt == NULL)
2907 return;
2908
2909 xmlHashFree(ctxt->funcHash, NULL);
2910 ctxt->funcHash = NULL;
2911}
2912
2913/************************************************************************
2914 * *
William M. Brack08171912003-12-29 02:52:11 +00002915 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00002916 * *
2917 ************************************************************************/
2918
2919/**
2920 * xmlXPathRegisterVariable:
2921 * @ctxt: the XPath context
2922 * @name: the variable name
2923 * @value: the variable value or NULL
2924 *
2925 * Register a new variable value. If @value is NULL it unregisters
2926 * the variable
2927 *
2928 * Returns 0 in case of success, -1 in case of error
2929 */
2930int
2931xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2932 xmlXPathObjectPtr value) {
2933 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2934}
2935
2936/**
2937 * xmlXPathRegisterVariableNS:
2938 * @ctxt: the XPath context
2939 * @name: the variable name
2940 * @ns_uri: the variable namespace URI
2941 * @value: the variable value or NULL
2942 *
2943 * Register a new variable value. If @value is NULL it unregisters
2944 * the variable
2945 *
2946 * Returns 0 in case of success, -1 in case of error
2947 */
2948int
2949xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2950 const xmlChar *ns_uri,
2951 xmlXPathObjectPtr value) {
2952 if (ctxt == NULL)
2953 return(-1);
2954 if (name == NULL)
2955 return(-1);
2956
2957 if (ctxt->varHash == NULL)
2958 ctxt->varHash = xmlHashCreate(0);
2959 if (ctxt->varHash == NULL)
2960 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002961 if (value == NULL)
2962 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2963 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002964 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2965 (void *) value,
2966 (xmlHashDeallocator)xmlXPathFreeObject));
2967}
2968
2969/**
2970 * xmlXPathRegisterVariableLookup:
2971 * @ctxt: the XPath context
2972 * @f: the lookup function
2973 * @data: the lookup data
2974 *
2975 * register an external mechanism to do variable lookup
2976 */
2977void
2978xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2979 xmlXPathVariableLookupFunc f, void *data) {
2980 if (ctxt == NULL)
2981 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002982 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00002983 ctxt->varLookupData = data;
2984}
2985
2986/**
2987 * xmlXPathVariableLookup:
2988 * @ctxt: the XPath context
2989 * @name: the variable name
2990 *
2991 * Search in the Variable array of the context for the given
2992 * variable value.
2993 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002994 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002995 */
2996xmlXPathObjectPtr
2997xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2998 if (ctxt == NULL)
2999 return(NULL);
3000
3001 if (ctxt->varLookupFunc != NULL) {
3002 xmlXPathObjectPtr ret;
3003
3004 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3005 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00003006 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003007 }
3008 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3009}
3010
3011/**
3012 * xmlXPathVariableLookupNS:
3013 * @ctxt: the XPath context
3014 * @name: the variable name
3015 * @ns_uri: the variable namespace URI
3016 *
3017 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00003018 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00003019 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003020 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003021 */
3022xmlXPathObjectPtr
3023xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3024 const xmlChar *ns_uri) {
3025 if (ctxt == NULL)
3026 return(NULL);
3027
3028 if (ctxt->varLookupFunc != NULL) {
3029 xmlXPathObjectPtr ret;
3030
3031 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3032 (ctxt->varLookupData, name, ns_uri);
3033 if (ret != NULL) return(ret);
3034 }
3035
3036 if (ctxt->varHash == NULL)
3037 return(NULL);
3038 if (name == NULL)
3039 return(NULL);
3040
Daniel Veillard8c357d52001-07-03 23:43:33 +00003041 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3042 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00003043}
3044
3045/**
3046 * xmlXPathRegisteredVariablesCleanup:
3047 * @ctxt: the XPath context
3048 *
3049 * Cleanup the XPath context data associated to registered variables
3050 */
3051void
3052xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3053 if (ctxt == NULL)
3054 return;
3055
Daniel Veillard76d66f42001-05-16 21:05:17 +00003056 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00003057 ctxt->varHash = NULL;
3058}
3059
3060/**
3061 * xmlXPathRegisterNs:
3062 * @ctxt: the XPath context
3063 * @prefix: the namespace prefix
3064 * @ns_uri: the namespace name
3065 *
3066 * Register a new namespace. If @ns_uri is NULL it unregisters
3067 * the namespace
3068 *
3069 * Returns 0 in case of success, -1 in case of error
3070 */
3071int
3072xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3073 const xmlChar *ns_uri) {
3074 if (ctxt == NULL)
3075 return(-1);
3076 if (prefix == NULL)
3077 return(-1);
3078
3079 if (ctxt->nsHash == NULL)
3080 ctxt->nsHash = xmlHashCreate(10);
3081 if (ctxt->nsHash == NULL)
3082 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003083 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003084 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003085 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003086 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003087 (xmlHashDeallocator)xmlFree));
3088}
3089
3090/**
3091 * xmlXPathNsLookup:
3092 * @ctxt: the XPath context
3093 * @prefix: the namespace prefix value
3094 *
3095 * Search in the namespace declaration array of the context for the given
3096 * namespace name associated to the given prefix
3097 *
3098 * Returns the value or NULL if not found
3099 */
3100const xmlChar *
3101xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3102 if (ctxt == NULL)
3103 return(NULL);
3104 if (prefix == NULL)
3105 return(NULL);
3106
3107#ifdef XML_XML_NAMESPACE
3108 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3109 return(XML_XML_NAMESPACE);
3110#endif
3111
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003112 if (ctxt->namespaces != NULL) {
3113 int i;
3114
3115 for (i = 0;i < ctxt->nsNr;i++) {
3116 if ((ctxt->namespaces[i] != NULL) &&
3117 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3118 return(ctxt->namespaces[i]->href);
3119 }
3120 }
Owen Taylor3473f882001-02-23 17:55:21 +00003121
3122 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3123}
3124
3125/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003126 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003127 * @ctxt: the XPath context
3128 *
3129 * Cleanup the XPath context data associated to registered variables
3130 */
3131void
3132xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3133 if (ctxt == NULL)
3134 return;
3135
Daniel Veillard42766c02002-08-22 20:52:17 +00003136 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003137 ctxt->nsHash = NULL;
3138}
3139
3140/************************************************************************
3141 * *
3142 * Routines to handle Values *
3143 * *
3144 ************************************************************************/
3145
William M. Brack08171912003-12-29 02:52:11 +00003146/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003147
3148/**
3149 * xmlXPathNewFloat:
3150 * @val: the double value
3151 *
3152 * Create a new xmlXPathObjectPtr of type double and of value @val
3153 *
3154 * Returns the newly created object.
3155 */
3156xmlXPathObjectPtr
3157xmlXPathNewFloat(double val) {
3158 xmlXPathObjectPtr ret;
3159
3160 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3161 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003162 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003163 return(NULL);
3164 }
3165 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3166 ret->type = XPATH_NUMBER;
3167 ret->floatval = val;
3168 return(ret);
3169}
3170
3171/**
3172 * xmlXPathNewBoolean:
3173 * @val: the boolean value
3174 *
3175 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3176 *
3177 * Returns the newly created object.
3178 */
3179xmlXPathObjectPtr
3180xmlXPathNewBoolean(int val) {
3181 xmlXPathObjectPtr ret;
3182
3183 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3184 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003185 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003186 return(NULL);
3187 }
3188 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3189 ret->type = XPATH_BOOLEAN;
3190 ret->boolval = (val != 0);
3191 return(ret);
3192}
3193
3194/**
3195 * xmlXPathNewString:
3196 * @val: the xmlChar * value
3197 *
3198 * Create a new xmlXPathObjectPtr of type string and of value @val
3199 *
3200 * Returns the newly created object.
3201 */
3202xmlXPathObjectPtr
3203xmlXPathNewString(const xmlChar *val) {
3204 xmlXPathObjectPtr ret;
3205
3206 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3207 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003208 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003209 return(NULL);
3210 }
3211 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3212 ret->type = XPATH_STRING;
3213 if (val != NULL)
3214 ret->stringval = xmlStrdup(val);
3215 else
3216 ret->stringval = xmlStrdup((const xmlChar *)"");
3217 return(ret);
3218}
3219
3220/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003221 * xmlXPathWrapString:
3222 * @val: the xmlChar * value
3223 *
3224 * Wraps the @val string into an XPath object.
3225 *
3226 * Returns the newly created object.
3227 */
3228xmlXPathObjectPtr
3229xmlXPathWrapString (xmlChar *val) {
3230 xmlXPathObjectPtr ret;
3231
3232 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3233 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003234 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003235 return(NULL);
3236 }
3237 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3238 ret->type = XPATH_STRING;
3239 ret->stringval = val;
3240 return(ret);
3241}
3242
3243/**
Owen Taylor3473f882001-02-23 17:55:21 +00003244 * xmlXPathNewCString:
3245 * @val: the char * value
3246 *
3247 * Create a new xmlXPathObjectPtr of type string and of value @val
3248 *
3249 * Returns the newly created object.
3250 */
3251xmlXPathObjectPtr
3252xmlXPathNewCString(const char *val) {
3253 xmlXPathObjectPtr ret;
3254
3255 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3256 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003257 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003258 return(NULL);
3259 }
3260 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3261 ret->type = XPATH_STRING;
3262 ret->stringval = xmlStrdup(BAD_CAST val);
3263 return(ret);
3264}
3265
3266/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003267 * xmlXPathWrapCString:
3268 * @val: the char * value
3269 *
3270 * Wraps a string into an XPath object.
3271 *
3272 * Returns the newly created object.
3273 */
3274xmlXPathObjectPtr
3275xmlXPathWrapCString (char * val) {
3276 return(xmlXPathWrapString((xmlChar *)(val)));
3277}
3278
3279/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003280 * xmlXPathWrapExternal:
3281 * @val: the user data
3282 *
3283 * Wraps the @val data into an XPath object.
3284 *
3285 * Returns the newly created object.
3286 */
3287xmlXPathObjectPtr
3288xmlXPathWrapExternal (void *val) {
3289 xmlXPathObjectPtr ret;
3290
3291 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3292 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003293 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003294 return(NULL);
3295 }
3296 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3297 ret->type = XPATH_USERS;
3298 ret->user = val;
3299 return(ret);
3300}
3301
3302/**
Owen Taylor3473f882001-02-23 17:55:21 +00003303 * xmlXPathObjectCopy:
3304 * @val: the original object
3305 *
3306 * allocate a new copy of a given object
3307 *
3308 * Returns the newly created object.
3309 */
3310xmlXPathObjectPtr
3311xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3312 xmlXPathObjectPtr ret;
3313
3314 if (val == NULL)
3315 return(NULL);
3316
3317 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3318 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003319 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003320 return(NULL);
3321 }
3322 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3323 switch (val->type) {
3324 case XPATH_BOOLEAN:
3325 case XPATH_NUMBER:
3326 case XPATH_POINT:
3327 case XPATH_RANGE:
3328 break;
3329 case XPATH_STRING:
3330 ret->stringval = xmlStrdup(val->stringval);
3331 break;
3332 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00003333#if 0
3334/*
3335 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
3336 this previous handling is no longer correct, and can cause some serious
3337 problems (ref. bug 145547)
3338*/
Owen Taylor3473f882001-02-23 17:55:21 +00003339 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003340 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003341 xmlNodePtr cur, tmp;
3342 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003343
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003344 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003345 top = xmlNewDoc(NULL);
3346 top->name = (char *)
3347 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003348 ret->user = top;
3349 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003350 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003351 cur = val->nodesetval->nodeTab[0]->children;
3352 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003353 tmp = xmlDocCopyNode(cur, top, 1);
3354 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003355 cur = cur->next;
3356 }
3357 }
William M. Bracke9449c52004-07-11 14:41:20 +00003358
Daniel Veillard9adc0462003-03-24 18:39:54 +00003359 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003360 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003361 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003362 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003363 break;
William M. Bracke9449c52004-07-11 14:41:20 +00003364#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003365 case XPATH_NODESET:
3366 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003367 /* Do not deallocate the copied tree value */
3368 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003369 break;
3370 case XPATH_LOCATIONSET:
3371#ifdef LIBXML_XPTR_ENABLED
3372 {
3373 xmlLocationSetPtr loc = val->user;
3374 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3375 break;
3376 }
3377#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003378 case XPATH_USERS:
3379 ret->user = val->user;
3380 break;
3381 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003382 xmlGenericError(xmlGenericErrorContext,
3383 "xmlXPathObjectCopy: unsupported type %d\n",
3384 val->type);
3385 break;
3386 }
3387 return(ret);
3388}
3389
3390/**
3391 * xmlXPathFreeObject:
3392 * @obj: the object to free
3393 *
3394 * Free up an xmlXPathObjectPtr object.
3395 */
3396void
3397xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3398 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003399 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003400 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00003401#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003402 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003403 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003404 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003405 } else
3406#endif
3407 if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003408 xmlXPathFreeValueTree(obj->nodesetval);
3409 } else {
3410 if (obj->nodesetval != NULL)
3411 xmlXPathFreeNodeSet(obj->nodesetval);
3412 }
Owen Taylor3473f882001-02-23 17:55:21 +00003413#ifdef LIBXML_XPTR_ENABLED
3414 } else if (obj->type == XPATH_LOCATIONSET) {
3415 if (obj->user != NULL)
3416 xmlXPtrFreeLocationSet(obj->user);
3417#endif
3418 } else if (obj->type == XPATH_STRING) {
3419 if (obj->stringval != NULL)
3420 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003421 }
3422
Owen Taylor3473f882001-02-23 17:55:21 +00003423 xmlFree(obj);
3424}
3425
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003426
3427/************************************************************************
3428 * *
3429 * Type Casting Routines *
3430 * *
3431 ************************************************************************/
3432
3433/**
3434 * xmlXPathCastBooleanToString:
3435 * @val: a boolean
3436 *
3437 * Converts a boolean to its string value.
3438 *
3439 * Returns a newly allocated string.
3440 */
3441xmlChar *
3442xmlXPathCastBooleanToString (int val) {
3443 xmlChar *ret;
3444 if (val)
3445 ret = xmlStrdup((const xmlChar *) "true");
3446 else
3447 ret = xmlStrdup((const xmlChar *) "false");
3448 return(ret);
3449}
3450
3451/**
3452 * xmlXPathCastNumberToString:
3453 * @val: a number
3454 *
3455 * Converts a number to its string value.
3456 *
3457 * Returns a newly allocated string.
3458 */
3459xmlChar *
3460xmlXPathCastNumberToString (double val) {
3461 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003462 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003463 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003464 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003465 break;
3466 case -1:
3467 ret = xmlStrdup((const xmlChar *) "-Infinity");
3468 break;
3469 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003470 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003471 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003472 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3473 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003474 } else {
3475 /* could be improved */
3476 char buf[100];
3477 xmlXPathFormatNumber(val, buf, 100);
3478 ret = xmlStrdup((const xmlChar *) buf);
3479 }
3480 }
3481 return(ret);
3482}
3483
3484/**
3485 * xmlXPathCastNodeToString:
3486 * @node: a node
3487 *
3488 * Converts a node to its string value.
3489 *
3490 * Returns a newly allocated string.
3491 */
3492xmlChar *
3493xmlXPathCastNodeToString (xmlNodePtr node) {
3494 return(xmlNodeGetContent(node));
3495}
3496
3497/**
3498 * xmlXPathCastNodeSetToString:
3499 * @ns: a node-set
3500 *
3501 * Converts a node-set to its string value.
3502 *
3503 * Returns a newly allocated string.
3504 */
3505xmlChar *
3506xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3507 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3508 return(xmlStrdup((const xmlChar *) ""));
3509
3510 xmlXPathNodeSetSort(ns);
3511 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3512}
3513
3514/**
3515 * xmlXPathCastToString:
3516 * @val: an XPath object
3517 *
3518 * Converts an existing object to its string() equivalent
3519 *
3520 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003521 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003522 * string object).
3523 */
3524xmlChar *
3525xmlXPathCastToString(xmlXPathObjectPtr val) {
3526 xmlChar *ret = NULL;
3527
3528 if (val == NULL)
3529 return(xmlStrdup((const xmlChar *) ""));
3530 switch (val->type) {
3531 case XPATH_UNDEFINED:
3532#ifdef DEBUG_EXPR
3533 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3534#endif
3535 ret = xmlStrdup((const xmlChar *) "");
3536 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003537 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003538 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003539 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3540 break;
3541 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003542 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003543 case XPATH_BOOLEAN:
3544 ret = xmlXPathCastBooleanToString(val->boolval);
3545 break;
3546 case XPATH_NUMBER: {
3547 ret = xmlXPathCastNumberToString(val->floatval);
3548 break;
3549 }
3550 case XPATH_USERS:
3551 case XPATH_POINT:
3552 case XPATH_RANGE:
3553 case XPATH_LOCATIONSET:
3554 TODO
3555 ret = xmlStrdup((const xmlChar *) "");
3556 break;
3557 }
3558 return(ret);
3559}
3560
3561/**
3562 * xmlXPathConvertString:
3563 * @val: an XPath object
3564 *
3565 * Converts an existing object to its string() equivalent
3566 *
3567 * Returns the new object, the old one is freed (or the operation
3568 * is done directly on @val)
3569 */
3570xmlXPathObjectPtr
3571xmlXPathConvertString(xmlXPathObjectPtr val) {
3572 xmlChar *res = NULL;
3573
3574 if (val == NULL)
3575 return(xmlXPathNewCString(""));
3576
3577 switch (val->type) {
3578 case XPATH_UNDEFINED:
3579#ifdef DEBUG_EXPR
3580 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3581#endif
3582 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003583 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003584 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003585 res = xmlXPathCastNodeSetToString(val->nodesetval);
3586 break;
3587 case XPATH_STRING:
3588 return(val);
3589 case XPATH_BOOLEAN:
3590 res = xmlXPathCastBooleanToString(val->boolval);
3591 break;
3592 case XPATH_NUMBER:
3593 res = xmlXPathCastNumberToString(val->floatval);
3594 break;
3595 case XPATH_USERS:
3596 case XPATH_POINT:
3597 case XPATH_RANGE:
3598 case XPATH_LOCATIONSET:
3599 TODO;
3600 break;
3601 }
3602 xmlXPathFreeObject(val);
3603 if (res == NULL)
3604 return(xmlXPathNewCString(""));
3605 return(xmlXPathWrapString(res));
3606}
3607
3608/**
3609 * xmlXPathCastBooleanToNumber:
3610 * @val: a boolean
3611 *
3612 * Converts a boolean to its number value
3613 *
3614 * Returns the number value
3615 */
3616double
3617xmlXPathCastBooleanToNumber(int val) {
3618 if (val)
3619 return(1.0);
3620 return(0.0);
3621}
3622
3623/**
3624 * xmlXPathCastStringToNumber:
3625 * @val: a string
3626 *
3627 * Converts a string to its number value
3628 *
3629 * Returns the number value
3630 */
3631double
3632xmlXPathCastStringToNumber(const xmlChar * val) {
3633 return(xmlXPathStringEvalNumber(val));
3634}
3635
3636/**
3637 * xmlXPathCastNodeToNumber:
3638 * @node: a node
3639 *
3640 * Converts a node to its number value
3641 *
3642 * Returns the number value
3643 */
3644double
3645xmlXPathCastNodeToNumber (xmlNodePtr node) {
3646 xmlChar *strval;
3647 double ret;
3648
3649 if (node == NULL)
3650 return(xmlXPathNAN);
3651 strval = xmlXPathCastNodeToString(node);
3652 if (strval == NULL)
3653 return(xmlXPathNAN);
3654 ret = xmlXPathCastStringToNumber(strval);
3655 xmlFree(strval);
3656
3657 return(ret);
3658}
3659
3660/**
3661 * xmlXPathCastNodeSetToNumber:
3662 * @ns: a node-set
3663 *
3664 * Converts a node-set to its number value
3665 *
3666 * Returns the number value
3667 */
3668double
3669xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3670 xmlChar *str;
3671 double ret;
3672
3673 if (ns == NULL)
3674 return(xmlXPathNAN);
3675 str = xmlXPathCastNodeSetToString(ns);
3676 ret = xmlXPathCastStringToNumber(str);
3677 xmlFree(str);
3678 return(ret);
3679}
3680
3681/**
3682 * xmlXPathCastToNumber:
3683 * @val: an XPath object
3684 *
3685 * Converts an XPath object to its number value
3686 *
3687 * Returns the number value
3688 */
3689double
3690xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3691 double ret = 0.0;
3692
3693 if (val == NULL)
3694 return(xmlXPathNAN);
3695 switch (val->type) {
3696 case XPATH_UNDEFINED:
3697#ifdef DEGUB_EXPR
3698 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3699#endif
3700 ret = xmlXPathNAN;
3701 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003702 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003703 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003704 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3705 break;
3706 case XPATH_STRING:
3707 ret = xmlXPathCastStringToNumber(val->stringval);
3708 break;
3709 case XPATH_NUMBER:
3710 ret = val->floatval;
3711 break;
3712 case XPATH_BOOLEAN:
3713 ret = xmlXPathCastBooleanToNumber(val->boolval);
3714 break;
3715 case XPATH_USERS:
3716 case XPATH_POINT:
3717 case XPATH_RANGE:
3718 case XPATH_LOCATIONSET:
3719 TODO;
3720 ret = xmlXPathNAN;
3721 break;
3722 }
3723 return(ret);
3724}
3725
3726/**
3727 * xmlXPathConvertNumber:
3728 * @val: an XPath object
3729 *
3730 * Converts an existing object to its number() equivalent
3731 *
3732 * Returns the new object, the old one is freed (or the operation
3733 * is done directly on @val)
3734 */
3735xmlXPathObjectPtr
3736xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3737 xmlXPathObjectPtr ret;
3738
3739 if (val == NULL)
3740 return(xmlXPathNewFloat(0.0));
3741 if (val->type == XPATH_NUMBER)
3742 return(val);
3743 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3744 xmlXPathFreeObject(val);
3745 return(ret);
3746}
3747
3748/**
3749 * xmlXPathCastNumberToBoolean:
3750 * @val: a number
3751 *
3752 * Converts a number to its boolean value
3753 *
3754 * Returns the boolean value
3755 */
3756int
3757xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003758 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003759 return(0);
3760 return(1);
3761}
3762
3763/**
3764 * xmlXPathCastStringToBoolean:
3765 * @val: a string
3766 *
3767 * Converts a string to its boolean value
3768 *
3769 * Returns the boolean value
3770 */
3771int
3772xmlXPathCastStringToBoolean (const xmlChar *val) {
3773 if ((val == NULL) || (xmlStrlen(val) == 0))
3774 return(0);
3775 return(1);
3776}
3777
3778/**
3779 * xmlXPathCastNodeSetToBoolean:
3780 * @ns: a node-set
3781 *
3782 * Converts a node-set to its boolean value
3783 *
3784 * Returns the boolean value
3785 */
3786int
3787xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3788 if ((ns == NULL) || (ns->nodeNr == 0))
3789 return(0);
3790 return(1);
3791}
3792
3793/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003794 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003795 * @val: an XPath object
3796 *
3797 * Converts an XPath object to its boolean value
3798 *
3799 * Returns the boolean value
3800 */
3801int
3802xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3803 int ret = 0;
3804
3805 if (val == NULL)
3806 return(0);
3807 switch (val->type) {
3808 case XPATH_UNDEFINED:
3809#ifdef DEBUG_EXPR
3810 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3811#endif
3812 ret = 0;
3813 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003814 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003815 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003816 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3817 break;
3818 case XPATH_STRING:
3819 ret = xmlXPathCastStringToBoolean(val->stringval);
3820 break;
3821 case XPATH_NUMBER:
3822 ret = xmlXPathCastNumberToBoolean(val->floatval);
3823 break;
3824 case XPATH_BOOLEAN:
3825 ret = val->boolval;
3826 break;
3827 case XPATH_USERS:
3828 case XPATH_POINT:
3829 case XPATH_RANGE:
3830 case XPATH_LOCATIONSET:
3831 TODO;
3832 ret = 0;
3833 break;
3834 }
3835 return(ret);
3836}
3837
3838
3839/**
3840 * xmlXPathConvertBoolean:
3841 * @val: an XPath object
3842 *
3843 * Converts an existing object to its boolean() equivalent
3844 *
3845 * Returns the new object, the old one is freed (or the operation
3846 * is done directly on @val)
3847 */
3848xmlXPathObjectPtr
3849xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3850 xmlXPathObjectPtr ret;
3851
3852 if (val == NULL)
3853 return(xmlXPathNewBoolean(0));
3854 if (val->type == XPATH_BOOLEAN)
3855 return(val);
3856 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3857 xmlXPathFreeObject(val);
3858 return(ret);
3859}
3860
Owen Taylor3473f882001-02-23 17:55:21 +00003861/************************************************************************
3862 * *
3863 * Routines to handle XPath contexts *
3864 * *
3865 ************************************************************************/
3866
3867/**
3868 * xmlXPathNewContext:
3869 * @doc: the XML document
3870 *
3871 * Create a new xmlXPathContext
3872 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003873 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003874 */
3875xmlXPathContextPtr
3876xmlXPathNewContext(xmlDocPtr doc) {
3877 xmlXPathContextPtr ret;
3878
3879 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3880 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003881 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003882 return(NULL);
3883 }
3884 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3885 ret->doc = doc;
3886 ret->node = NULL;
3887
3888 ret->varHash = NULL;
3889
3890 ret->nb_types = 0;
3891 ret->max_types = 0;
3892 ret->types = NULL;
3893
3894 ret->funcHash = xmlHashCreate(0);
3895
3896 ret->nb_axis = 0;
3897 ret->max_axis = 0;
3898 ret->axis = NULL;
3899
3900 ret->nsHash = NULL;
3901 ret->user = NULL;
3902
3903 ret->contextSize = -1;
3904 ret->proximityPosition = -1;
3905
3906 xmlXPathRegisterAllFunctions(ret);
3907
3908 return(ret);
3909}
3910
3911/**
3912 * xmlXPathFreeContext:
3913 * @ctxt: the context to free
3914 *
3915 * Free up an xmlXPathContext
3916 */
3917void
3918xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3919 xmlXPathRegisteredNsCleanup(ctxt);
3920 xmlXPathRegisteredFuncsCleanup(ctxt);
3921 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003922 xmlFree(ctxt);
3923}
3924
3925/************************************************************************
3926 * *
3927 * Routines to handle XPath parser contexts *
3928 * *
3929 ************************************************************************/
3930
3931#define CHECK_CTXT(ctxt) \
3932 if (ctxt == NULL) { \
3933 xmlGenericError(xmlGenericErrorContext, \
3934 "%s:%d Internal error: ctxt == NULL\n", \
3935 __FILE__, __LINE__); \
3936 } \
3937
3938
3939#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00003940 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
3941 (ctxt->doc->children == NULL)) { \
3942 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00003943 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00003944 }
Owen Taylor3473f882001-02-23 17:55:21 +00003945
3946
3947/**
3948 * xmlXPathNewParserContext:
3949 * @str: the XPath expression
3950 * @ctxt: the XPath context
3951 *
3952 * Create a new xmlXPathParserContext
3953 *
3954 * Returns the xmlXPathParserContext just allocated.
3955 */
3956xmlXPathParserContextPtr
3957xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3958 xmlXPathParserContextPtr ret;
3959
3960 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3961 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003962 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003963 return(NULL);
3964 }
3965 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3966 ret->cur = ret->base = str;
3967 ret->context = ctxt;
3968
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003969 ret->comp = xmlXPathNewCompExpr();
3970 if (ret->comp == NULL) {
3971 xmlFree(ret->valueTab);
3972 xmlFree(ret);
3973 return(NULL);
3974 }
Daniel Veillard4773df22004-01-23 13:15:13 +00003975 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
3976 ret->comp->dict = ctxt->dict;
3977 xmlDictReference(ret->comp->dict);
3978 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003979
3980 return(ret);
3981}
3982
3983/**
3984 * xmlXPathCompParserContext:
3985 * @comp: the XPath compiled expression
3986 * @ctxt: the XPath context
3987 *
3988 * Create a new xmlXPathParserContext when processing a compiled expression
3989 *
3990 * Returns the xmlXPathParserContext just allocated.
3991 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003992static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003993xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3994 xmlXPathParserContextPtr ret;
3995
3996 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3997 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003998 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003999 return(NULL);
4000 }
4001 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4002
Owen Taylor3473f882001-02-23 17:55:21 +00004003 /* Allocate the value stack */
4004 ret->valueTab = (xmlXPathObjectPtr *)
4005 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004006 if (ret->valueTab == NULL) {
4007 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004008 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004009 return(NULL);
4010 }
Owen Taylor3473f882001-02-23 17:55:21 +00004011 ret->valueNr = 0;
4012 ret->valueMax = 10;
4013 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004014
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004015 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004016 ret->comp = comp;
4017
Owen Taylor3473f882001-02-23 17:55:21 +00004018 return(ret);
4019}
4020
4021/**
4022 * xmlXPathFreeParserContext:
4023 * @ctxt: the context to free
4024 *
4025 * Free up an xmlXPathParserContext
4026 */
4027void
4028xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
4029 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004030 xmlFree(ctxt->valueTab);
4031 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004032 if (ctxt->comp)
4033 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00004034 xmlFree(ctxt);
4035}
4036
4037/************************************************************************
4038 * *
4039 * The implicit core function library *
4040 * *
4041 ************************************************************************/
4042
Owen Taylor3473f882001-02-23 17:55:21 +00004043/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004044 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00004045 * @node: a node pointer
4046 *
4047 * Function computing the beginning of the string value of the node,
4048 * used to speed up comparisons
4049 *
4050 * Returns an int usable as a hash
4051 */
4052static unsigned int
4053xmlXPathNodeValHash(xmlNodePtr node) {
4054 int len = 2;
4055 const xmlChar * string = NULL;
4056 xmlNodePtr tmp = NULL;
4057 unsigned int ret = 0;
4058
4059 if (node == NULL)
4060 return(0);
4061
Daniel Veillard9adc0462003-03-24 18:39:54 +00004062 if (node->type == XML_DOCUMENT_NODE) {
4063 tmp = xmlDocGetRootElement((xmlDocPtr) node);
4064 if (tmp == NULL)
4065 node = node->children;
4066 else
4067 node = tmp;
4068
4069 if (node == NULL)
4070 return(0);
4071 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004072
4073 switch (node->type) {
4074 case XML_COMMENT_NODE:
4075 case XML_PI_NODE:
4076 case XML_CDATA_SECTION_NODE:
4077 case XML_TEXT_NODE:
4078 string = node->content;
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_NAMESPACE_DECL:
4086 string = ((xmlNsPtr)node)->href;
4087 if (string == NULL)
4088 return(0);
4089 if (string[0] == 0)
4090 return(0);
4091 return(((unsigned int) string[0]) +
4092 (((unsigned int) string[1]) << 8));
4093 case XML_ATTRIBUTE_NODE:
4094 tmp = ((xmlAttrPtr) node)->children;
4095 break;
4096 case XML_ELEMENT_NODE:
4097 tmp = node->children;
4098 break;
4099 default:
4100 return(0);
4101 }
4102 while (tmp != NULL) {
4103 switch (tmp->type) {
4104 case XML_COMMENT_NODE:
4105 case XML_PI_NODE:
4106 case XML_CDATA_SECTION_NODE:
4107 case XML_TEXT_NODE:
4108 string = tmp->content;
4109 break;
4110 case XML_NAMESPACE_DECL:
4111 string = ((xmlNsPtr)tmp)->href;
4112 break;
4113 default:
4114 break;
4115 }
4116 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004117 if (len == 1) {
4118 return(ret + (((unsigned int) string[0]) << 8));
4119 }
4120 if (string[1] == 0) {
4121 len = 1;
4122 ret = (unsigned int) string[0];
4123 } else {
4124 return(((unsigned int) string[0]) +
4125 (((unsigned int) string[1]) << 8));
4126 }
4127 }
4128 /*
4129 * Skip to next node
4130 */
4131 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4132 if (tmp->children->type != XML_ENTITY_DECL) {
4133 tmp = tmp->children;
4134 continue;
4135 }
4136 }
4137 if (tmp == node)
4138 break;
4139
4140 if (tmp->next != NULL) {
4141 tmp = tmp->next;
4142 continue;
4143 }
4144
4145 do {
4146 tmp = tmp->parent;
4147 if (tmp == NULL)
4148 break;
4149 if (tmp == node) {
4150 tmp = NULL;
4151 break;
4152 }
4153 if (tmp->next != NULL) {
4154 tmp = tmp->next;
4155 break;
4156 }
4157 } while (tmp != NULL);
4158 }
4159 return(ret);
4160}
4161
4162/**
4163 * xmlXPathStringHash:
4164 * @string: a string
4165 *
4166 * Function computing the beginning of the string value of the node,
4167 * used to speed up comparisons
4168 *
4169 * Returns an int usable as a hash
4170 */
4171static unsigned int
4172xmlXPathStringHash(const xmlChar * string) {
4173 if (string == NULL)
4174 return((unsigned int) 0);
4175 if (string[0] == 0)
4176 return(0);
4177 return(((unsigned int) string[0]) +
4178 (((unsigned int) string[1]) << 8));
4179}
4180
4181/**
Owen Taylor3473f882001-02-23 17:55:21 +00004182 * xmlXPathCompareNodeSetFloat:
4183 * @ctxt: the XPath Parser context
4184 * @inf: less than (1) or greater than (0)
4185 * @strict: is the comparison strict
4186 * @arg: the node set
4187 * @f: the value
4188 *
4189 * Implement the compare operation between a nodeset and a number
4190 * @ns < @val (1, 1, ...
4191 * @ns <= @val (1, 0, ...
4192 * @ns > @val (0, 1, ...
4193 * @ns >= @val (0, 0, ...
4194 *
4195 * If one object to be compared is a node-set and the other is a number,
4196 * then the comparison will be true if and only if there is a node in the
4197 * node-set such that the result of performing the comparison on the number
4198 * to be compared and on the result of converting the string-value of that
4199 * node to a number using the number function is true.
4200 *
4201 * Returns 0 or 1 depending on the results of the test.
4202 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004203static int
Owen Taylor3473f882001-02-23 17:55:21 +00004204xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4205 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4206 int i, ret = 0;
4207 xmlNodeSetPtr ns;
4208 xmlChar *str2;
4209
4210 if ((f == NULL) || (arg == NULL) ||
4211 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4212 xmlXPathFreeObject(arg);
4213 xmlXPathFreeObject(f);
4214 return(0);
4215 }
4216 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004217 if (ns != NULL) {
4218 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004219 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004220 if (str2 != NULL) {
4221 valuePush(ctxt,
4222 xmlXPathNewString(str2));
4223 xmlFree(str2);
4224 xmlXPathNumberFunction(ctxt, 1);
4225 valuePush(ctxt, xmlXPathObjectCopy(f));
4226 ret = xmlXPathCompareValues(ctxt, inf, strict);
4227 if (ret)
4228 break;
4229 }
4230 }
Owen Taylor3473f882001-02-23 17:55:21 +00004231 }
4232 xmlXPathFreeObject(arg);
4233 xmlXPathFreeObject(f);
4234 return(ret);
4235}
4236
4237/**
4238 * xmlXPathCompareNodeSetString:
4239 * @ctxt: the XPath Parser context
4240 * @inf: less than (1) or greater than (0)
4241 * @strict: is the comparison strict
4242 * @arg: the node set
4243 * @s: the value
4244 *
4245 * Implement the compare operation between a nodeset and a string
4246 * @ns < @val (1, 1, ...
4247 * @ns <= @val (1, 0, ...
4248 * @ns > @val (0, 1, ...
4249 * @ns >= @val (0, 0, ...
4250 *
4251 * If one object to be compared is a node-set and the other is a string,
4252 * then the comparison will be true if and only if there is a node in
4253 * the node-set such that the result of performing the comparison on the
4254 * string-value of the node and the other string is true.
4255 *
4256 * Returns 0 or 1 depending on the results of the test.
4257 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004258static int
Owen Taylor3473f882001-02-23 17:55:21 +00004259xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4260 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4261 int i, ret = 0;
4262 xmlNodeSetPtr ns;
4263 xmlChar *str2;
4264
4265 if ((s == NULL) || (arg == NULL) ||
4266 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4267 xmlXPathFreeObject(arg);
4268 xmlXPathFreeObject(s);
4269 return(0);
4270 }
4271 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004272 if (ns != NULL) {
4273 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004274 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004275 if (str2 != NULL) {
4276 valuePush(ctxt,
4277 xmlXPathNewString(str2));
4278 xmlFree(str2);
4279 valuePush(ctxt, xmlXPathObjectCopy(s));
4280 ret = xmlXPathCompareValues(ctxt, inf, strict);
4281 if (ret)
4282 break;
4283 }
4284 }
Owen Taylor3473f882001-02-23 17:55:21 +00004285 }
4286 xmlXPathFreeObject(arg);
4287 xmlXPathFreeObject(s);
4288 return(ret);
4289}
4290
4291/**
4292 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004293 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004294 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004295 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004296 * @arg2: the second node set object
4297 *
4298 * Implement the compare operation on nodesets:
4299 *
4300 * If both objects to be compared are node-sets, then the comparison
4301 * will be true if and only if there is a node in the first node-set
4302 * and a node in the second node-set such that the result of performing
4303 * the comparison on the string-values of the two nodes is true.
4304 * ....
4305 * When neither object to be compared is a node-set and the operator
4306 * is <=, <, >= or >, then the objects are compared by converting both
4307 * objects to numbers and comparing the numbers according to IEEE 754.
4308 * ....
4309 * The number function converts its argument to a number as follows:
4310 * - a string that consists of optional whitespace followed by an
4311 * optional minus sign followed by a Number followed by whitespace
4312 * is converted to the IEEE 754 number that is nearest (according
4313 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4314 * represented by the string; any other string is converted to NaN
4315 *
4316 * Conclusion all nodes need to be converted first to their string value
4317 * and then the comparison must be done when possible
4318 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004319static int
4320xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004321 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4322 int i, j, init = 0;
4323 double val1;
4324 double *values2;
4325 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004326 xmlNodeSetPtr ns1;
4327 xmlNodeSetPtr ns2;
4328
4329 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004330 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4331 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004332 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004333 }
Owen Taylor3473f882001-02-23 17:55:21 +00004334 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004335 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4336 xmlXPathFreeObject(arg1);
4337 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004338 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004339 }
Owen Taylor3473f882001-02-23 17:55:21 +00004340
4341 ns1 = arg1->nodesetval;
4342 ns2 = arg2->nodesetval;
4343
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004344 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004345 xmlXPathFreeObject(arg1);
4346 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004347 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004348 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004349 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004350 xmlXPathFreeObject(arg1);
4351 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004352 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004353 }
Owen Taylor3473f882001-02-23 17:55:21 +00004354
4355 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4356 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004357 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004358 xmlXPathFreeObject(arg1);
4359 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004360 return(0);
4361 }
4362 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004363 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004364 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004365 continue;
4366 for (j = 0;j < ns2->nodeNr;j++) {
4367 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004368 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004369 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004370 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004371 continue;
4372 if (inf && strict)
4373 ret = (val1 < values2[j]);
4374 else if (inf && !strict)
4375 ret = (val1 <= values2[j]);
4376 else if (!inf && strict)
4377 ret = (val1 > values2[j]);
4378 else if (!inf && !strict)
4379 ret = (val1 >= values2[j]);
4380 if (ret)
4381 break;
4382 }
4383 if (ret)
4384 break;
4385 init = 1;
4386 }
4387 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004388 xmlXPathFreeObject(arg1);
4389 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004390 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004391}
4392
4393/**
4394 * xmlXPathCompareNodeSetValue:
4395 * @ctxt: the XPath Parser context
4396 * @inf: less than (1) or greater than (0)
4397 * @strict: is the comparison strict
4398 * @arg: the node set
4399 * @val: the value
4400 *
4401 * Implement the compare operation between a nodeset and a value
4402 * @ns < @val (1, 1, ...
4403 * @ns <= @val (1, 0, ...
4404 * @ns > @val (0, 1, ...
4405 * @ns >= @val (0, 0, ...
4406 *
4407 * If one object to be compared is a node-set and the other is a boolean,
4408 * then the comparison will be true if and only if the result of performing
4409 * the comparison on the boolean and on the result of converting
4410 * the node-set to a boolean using the boolean function is true.
4411 *
4412 * Returns 0 or 1 depending on the results of the test.
4413 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004414static int
Owen Taylor3473f882001-02-23 17:55:21 +00004415xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4416 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4417 if ((val == NULL) || (arg == NULL) ||
4418 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4419 return(0);
4420
4421 switch(val->type) {
4422 case XPATH_NUMBER:
4423 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4424 case XPATH_NODESET:
4425 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004426 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004427 case XPATH_STRING:
4428 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4429 case XPATH_BOOLEAN:
4430 valuePush(ctxt, arg);
4431 xmlXPathBooleanFunction(ctxt, 1);
4432 valuePush(ctxt, val);
4433 return(xmlXPathCompareValues(ctxt, inf, strict));
4434 default:
4435 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004436 }
4437 return(0);
4438}
4439
4440/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004441 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004442 * @arg: the nodeset object argument
4443 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004444 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004445 *
4446 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4447 * If one object to be compared is a node-set and the other is a string,
4448 * then the comparison will be true if and only if there is a node in
4449 * the node-set such that the result of performing the comparison on the
4450 * string-value of the node and the other string is true.
4451 *
4452 * Returns 0 or 1 depending on the results of the test.
4453 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004454static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004455xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004456{
Owen Taylor3473f882001-02-23 17:55:21 +00004457 int i;
4458 xmlNodeSetPtr ns;
4459 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004460 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004461
4462 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004463 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4464 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004465 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004466 /*
4467 * A NULL nodeset compared with a string is always false
4468 * (since there is no node equal, and no node not equal)
4469 */
4470 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004471 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004472 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004473 for (i = 0; i < ns->nodeNr; i++) {
4474 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4475 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4476 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4477 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004478 if (neq)
4479 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004480 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004481 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4482 if (neq)
4483 continue;
4484 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004485 } else if (neq) {
4486 if (str2 != NULL)
4487 xmlFree(str2);
4488 return (1);
4489 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004490 if (str2 != NULL)
4491 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004492 } else if (neq)
4493 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004494 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004495 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004496}
4497
4498/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004499 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004500 * @arg: the nodeset object argument
4501 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004502 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004503 *
4504 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4505 * If one object to be compared is a node-set and the other is a number,
4506 * then the comparison will be true if and only if there is a node in
4507 * the node-set such that the result of performing the comparison on the
4508 * number to be compared and on the result of converting the string-value
4509 * of that node to a number using the number function is true.
4510 *
4511 * Returns 0 or 1 depending on the results of the test.
4512 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004513static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004514xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4515 xmlXPathObjectPtr arg, double f, int neq) {
4516 int i, ret=0;
4517 xmlNodeSetPtr ns;
4518 xmlChar *str2;
4519 xmlXPathObjectPtr val;
4520 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004521
4522 if ((arg == NULL) ||
4523 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4524 return(0);
4525
William M. Brack0c022ad2002-07-12 00:56:01 +00004526 ns = arg->nodesetval;
4527 if (ns != NULL) {
4528 for (i=0;i<ns->nodeNr;i++) {
4529 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4530 if (str2 != NULL) {
4531 valuePush(ctxt, xmlXPathNewString(str2));
4532 xmlFree(str2);
4533 xmlXPathNumberFunction(ctxt, 1);
4534 val = valuePop(ctxt);
4535 v = val->floatval;
4536 xmlXPathFreeObject(val);
4537 if (!xmlXPathIsNaN(v)) {
4538 if ((!neq) && (v==f)) {
4539 ret = 1;
4540 break;
4541 } else if ((neq) && (v!=f)) {
4542 ret = 1;
4543 break;
4544 }
4545 }
4546 }
4547 }
4548 }
4549
4550 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004551}
4552
4553
4554/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004555 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004556 * @arg1: first nodeset object argument
4557 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004558 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004559 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004560 * Implement the equal / not equal operation on XPath nodesets:
4561 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004562 * If both objects to be compared are node-sets, then the comparison
4563 * will be true if and only if there is a node in the first node-set and
4564 * a node in the second node-set such that the result of performing the
4565 * comparison on the string-values of the two nodes is true.
4566 *
4567 * (needless to say, this is a costly operation)
4568 *
4569 * Returns 0 or 1 depending on the results of the test.
4570 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004571static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004572xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004573 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004574 unsigned int *hashs1;
4575 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004576 xmlChar **values1;
4577 xmlChar **values2;
4578 int ret = 0;
4579 xmlNodeSetPtr ns1;
4580 xmlNodeSetPtr ns2;
4581
4582 if ((arg1 == NULL) ||
4583 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4584 return(0);
4585 if ((arg2 == NULL) ||
4586 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4587 return(0);
4588
4589 ns1 = arg1->nodesetval;
4590 ns2 = arg2->nodesetval;
4591
Daniel Veillard911f49a2001-04-07 15:39:35 +00004592 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004593 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004594 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004595 return(0);
4596
4597 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004598 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004599 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004600 if (neq == 0)
4601 for (i = 0;i < ns1->nodeNr;i++)
4602 for (j = 0;j < ns2->nodeNr;j++)
4603 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4604 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004605
4606 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004607 if (values1 == NULL) {
4608 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004609 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004610 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004611 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4612 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004613 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004614 xmlFree(values1);
4615 return(0);
4616 }
Owen Taylor3473f882001-02-23 17:55:21 +00004617 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4618 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4619 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004620 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004621 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004622 xmlFree(values1);
4623 return(0);
4624 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004625 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4626 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004627 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004628 xmlFree(hashs1);
4629 xmlFree(values1);
4630 xmlFree(values2);
4631 return(0);
4632 }
Owen Taylor3473f882001-02-23 17:55:21 +00004633 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4634 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004635 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004636 for (j = 0;j < ns2->nodeNr;j++) {
4637 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004638 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004639 if (hashs1[i] != hashs2[j]) {
4640 if (neq) {
4641 ret = 1;
4642 break;
4643 }
4644 }
4645 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004646 if (values1[i] == NULL)
4647 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4648 if (values2[j] == NULL)
4649 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004650 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004651 if (ret)
4652 break;
4653 }
Owen Taylor3473f882001-02-23 17:55:21 +00004654 }
4655 if (ret)
4656 break;
4657 }
4658 for (i = 0;i < ns1->nodeNr;i++)
4659 if (values1[i] != NULL)
4660 xmlFree(values1[i]);
4661 for (j = 0;j < ns2->nodeNr;j++)
4662 if (values2[j] != NULL)
4663 xmlFree(values2[j]);
4664 xmlFree(values1);
4665 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004666 xmlFree(hashs1);
4667 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004668 return(ret);
4669}
4670
William M. Brack0c022ad2002-07-12 00:56:01 +00004671static int
4672xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4673 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004674 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004675 /*
4676 *At this point we are assured neither arg1 nor arg2
4677 *is a nodeset, so we can just pick the appropriate routine.
4678 */
Owen Taylor3473f882001-02-23 17:55:21 +00004679 switch (arg1->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 switch (arg2->type) {
4688 case XPATH_UNDEFINED:
4689#ifdef DEBUG_EXPR
4690 xmlGenericError(xmlGenericErrorContext,
4691 "Equal: undefined\n");
4692#endif
4693 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004694 case XPATH_BOOLEAN:
4695#ifdef DEBUG_EXPR
4696 xmlGenericError(xmlGenericErrorContext,
4697 "Equal: %d boolean %d \n",
4698 arg1->boolval, arg2->boolval);
4699#endif
4700 ret = (arg1->boolval == arg2->boolval);
4701 break;
4702 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004703 ret = (arg1->boolval ==
4704 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004705 break;
4706 case XPATH_STRING:
4707 if ((arg2->stringval == NULL) ||
4708 (arg2->stringval[0] == 0)) ret = 0;
4709 else
4710 ret = 1;
4711 ret = (arg1->boolval == ret);
4712 break;
4713 case XPATH_USERS:
4714 case XPATH_POINT:
4715 case XPATH_RANGE:
4716 case XPATH_LOCATIONSET:
4717 TODO
4718 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004719 case XPATH_NODESET:
4720 case XPATH_XSLT_TREE:
4721 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004722 }
4723 break;
4724 case XPATH_NUMBER:
4725 switch (arg2->type) {
4726 case XPATH_UNDEFINED:
4727#ifdef DEBUG_EXPR
4728 xmlGenericError(xmlGenericErrorContext,
4729 "Equal: undefined\n");
4730#endif
4731 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004732 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004733 ret = (arg2->boolval==
4734 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004735 break;
4736 case XPATH_STRING:
4737 valuePush(ctxt, arg2);
4738 xmlXPathNumberFunction(ctxt, 1);
4739 arg2 = valuePop(ctxt);
4740 /* no break on purpose */
4741 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004742 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004743 if (xmlXPathIsNaN(arg1->floatval) ||
4744 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004745 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004746 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4747 if (xmlXPathIsInf(arg2->floatval) == 1)
4748 ret = 1;
4749 else
4750 ret = 0;
4751 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4752 if (xmlXPathIsInf(arg2->floatval) == -1)
4753 ret = 1;
4754 else
4755 ret = 0;
4756 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4757 if (xmlXPathIsInf(arg1->floatval) == 1)
4758 ret = 1;
4759 else
4760 ret = 0;
4761 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4762 if (xmlXPathIsInf(arg1->floatval) == -1)
4763 ret = 1;
4764 else
4765 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004766 } else {
4767 ret = (arg1->floatval == arg2->floatval);
4768 }
Owen Taylor3473f882001-02-23 17:55:21 +00004769 break;
4770 case XPATH_USERS:
4771 case XPATH_POINT:
4772 case XPATH_RANGE:
4773 case XPATH_LOCATIONSET:
4774 TODO
4775 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004776 case XPATH_NODESET:
4777 case XPATH_XSLT_TREE:
4778 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004779 }
4780 break;
4781 case XPATH_STRING:
4782 switch (arg2->type) {
4783 case XPATH_UNDEFINED:
4784#ifdef DEBUG_EXPR
4785 xmlGenericError(xmlGenericErrorContext,
4786 "Equal: undefined\n");
4787#endif
4788 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004789 case XPATH_BOOLEAN:
4790 if ((arg1->stringval == NULL) ||
4791 (arg1->stringval[0] == 0)) ret = 0;
4792 else
4793 ret = 1;
4794 ret = (arg2->boolval == ret);
4795 break;
4796 case XPATH_STRING:
4797 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4798 break;
4799 case XPATH_NUMBER:
4800 valuePush(ctxt, arg1);
4801 xmlXPathNumberFunction(ctxt, 1);
4802 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004803 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004804 if (xmlXPathIsNaN(arg1->floatval) ||
4805 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004806 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004807 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4808 if (xmlXPathIsInf(arg2->floatval) == 1)
4809 ret = 1;
4810 else
4811 ret = 0;
4812 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4813 if (xmlXPathIsInf(arg2->floatval) == -1)
4814 ret = 1;
4815 else
4816 ret = 0;
4817 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4818 if (xmlXPathIsInf(arg1->floatval) == 1)
4819 ret = 1;
4820 else
4821 ret = 0;
4822 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4823 if (xmlXPathIsInf(arg1->floatval) == -1)
4824 ret = 1;
4825 else
4826 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004827 } else {
4828 ret = (arg1->floatval == arg2->floatval);
4829 }
Owen Taylor3473f882001-02-23 17:55:21 +00004830 break;
4831 case XPATH_USERS:
4832 case XPATH_POINT:
4833 case XPATH_RANGE:
4834 case XPATH_LOCATIONSET:
4835 TODO
4836 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004837 case XPATH_NODESET:
4838 case XPATH_XSLT_TREE:
4839 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004840 }
4841 break;
4842 case XPATH_USERS:
4843 case XPATH_POINT:
4844 case XPATH_RANGE:
4845 case XPATH_LOCATIONSET:
4846 TODO
4847 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004848 case XPATH_NODESET:
4849 case XPATH_XSLT_TREE:
4850 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004851 }
4852 xmlXPathFreeObject(arg1);
4853 xmlXPathFreeObject(arg2);
4854 return(ret);
4855}
4856
William M. Brack0c022ad2002-07-12 00:56:01 +00004857/**
4858 * xmlXPathEqualValues:
4859 * @ctxt: the XPath Parser context
4860 *
4861 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4862 *
4863 * Returns 0 or 1 depending on the results of the test.
4864 */
4865int
4866xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4867 xmlXPathObjectPtr arg1, arg2, argtmp;
4868 int ret = 0;
4869
Daniel Veillarda82b1822004-11-08 16:24:57 +00004870 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
William M. Brack0c022ad2002-07-12 00:56:01 +00004871 arg2 = valuePop(ctxt);
4872 arg1 = valuePop(ctxt);
4873 if ((arg1 == NULL) || (arg2 == NULL)) {
4874 if (arg1 != NULL)
4875 xmlXPathFreeObject(arg1);
4876 else
4877 xmlXPathFreeObject(arg2);
4878 XP_ERROR0(XPATH_INVALID_OPERAND);
4879 }
4880
4881 if (arg1 == arg2) {
4882#ifdef DEBUG_EXPR
4883 xmlGenericError(xmlGenericErrorContext,
4884 "Equal: by pointer\n");
4885#endif
4886 return(1);
4887 }
4888
4889 /*
4890 *If either argument is a nodeset, it's a 'special case'
4891 */
4892 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4893 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4894 /*
4895 *Hack it to assure arg1 is the nodeset
4896 */
4897 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4898 argtmp = arg2;
4899 arg2 = arg1;
4900 arg1 = argtmp;
4901 }
4902 switch (arg2->type) {
4903 case XPATH_UNDEFINED:
4904#ifdef DEBUG_EXPR
4905 xmlGenericError(xmlGenericErrorContext,
4906 "Equal: undefined\n");
4907#endif
4908 break;
4909 case XPATH_NODESET:
4910 case XPATH_XSLT_TREE:
4911 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4912 break;
4913 case XPATH_BOOLEAN:
4914 if ((arg1->nodesetval == NULL) ||
4915 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4916 else
4917 ret = 1;
4918 ret = (ret == arg2->boolval);
4919 break;
4920 case XPATH_NUMBER:
4921 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4922 break;
4923 case XPATH_STRING:
4924 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4925 break;
4926 case XPATH_USERS:
4927 case XPATH_POINT:
4928 case XPATH_RANGE:
4929 case XPATH_LOCATIONSET:
4930 TODO
4931 break;
4932 }
4933 xmlXPathFreeObject(arg1);
4934 xmlXPathFreeObject(arg2);
4935 return(ret);
4936 }
4937
4938 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4939}
4940
4941/**
4942 * xmlXPathNotEqualValues:
4943 * @ctxt: the XPath Parser context
4944 *
4945 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4946 *
4947 * Returns 0 or 1 depending on the results of the test.
4948 */
4949int
4950xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4951 xmlXPathObjectPtr arg1, arg2, argtmp;
4952 int ret = 0;
4953
Daniel Veillarda82b1822004-11-08 16:24:57 +00004954 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
William M. Brack0c022ad2002-07-12 00:56:01 +00004955 arg2 = valuePop(ctxt);
4956 arg1 = valuePop(ctxt);
4957 if ((arg1 == NULL) || (arg2 == NULL)) {
4958 if (arg1 != NULL)
4959 xmlXPathFreeObject(arg1);
4960 else
4961 xmlXPathFreeObject(arg2);
4962 XP_ERROR0(XPATH_INVALID_OPERAND);
4963 }
4964
4965 if (arg1 == arg2) {
4966#ifdef DEBUG_EXPR
4967 xmlGenericError(xmlGenericErrorContext,
4968 "NotEqual: by pointer\n");
4969#endif
4970 return(0);
4971 }
4972
4973 /*
4974 *If either argument is a nodeset, it's a 'special case'
4975 */
4976 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4977 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4978 /*
4979 *Hack it to assure arg1 is the nodeset
4980 */
4981 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4982 argtmp = arg2;
4983 arg2 = arg1;
4984 arg1 = argtmp;
4985 }
4986 switch (arg2->type) {
4987 case XPATH_UNDEFINED:
4988#ifdef DEBUG_EXPR
4989 xmlGenericError(xmlGenericErrorContext,
4990 "NotEqual: undefined\n");
4991#endif
4992 break;
4993 case XPATH_NODESET:
4994 case XPATH_XSLT_TREE:
4995 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4996 break;
4997 case XPATH_BOOLEAN:
4998 if ((arg1->nodesetval == NULL) ||
4999 (arg1->nodesetval->nodeNr == 0)) ret = 0;
5000 else
5001 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00005002 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00005003 break;
5004 case XPATH_NUMBER:
5005 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5006 break;
5007 case XPATH_STRING:
5008 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
5009 break;
5010 case XPATH_USERS:
5011 case XPATH_POINT:
5012 case XPATH_RANGE:
5013 case XPATH_LOCATIONSET:
5014 TODO
5015 break;
5016 }
5017 xmlXPathFreeObject(arg1);
5018 xmlXPathFreeObject(arg2);
5019 return(ret);
5020 }
5021
5022 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5023}
Owen Taylor3473f882001-02-23 17:55:21 +00005024
5025/**
5026 * xmlXPathCompareValues:
5027 * @ctxt: the XPath Parser context
5028 * @inf: less than (1) or greater than (0)
5029 * @strict: is the comparison strict
5030 *
5031 * Implement the compare operation on XPath objects:
5032 * @arg1 < @arg2 (1, 1, ...
5033 * @arg1 <= @arg2 (1, 0, ...
5034 * @arg1 > @arg2 (0, 1, ...
5035 * @arg1 >= @arg2 (0, 0, ...
5036 *
5037 * When neither object to be compared is a node-set and the operator is
5038 * <=, <, >=, >, then the objects are compared by converted both objects
5039 * to numbers and comparing the numbers according to IEEE 754. The <
5040 * comparison will be true if and only if the first number is less than the
5041 * second number. The <= comparison will be true if and only if the first
5042 * number is less than or equal to the second number. The > comparison
5043 * will be true if and only if the first number is greater than the second
5044 * number. The >= comparison will be true if and only if the first number
5045 * is greater than or equal to the second number.
5046 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005047 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005048 */
5049int
5050xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005051 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005052 xmlXPathObjectPtr arg1, arg2;
5053
Daniel Veillarda82b1822004-11-08 16:24:57 +00005054 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
William M. Brack0c022ad2002-07-12 00:56:01 +00005055 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005056 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005057 if ((arg1 == NULL) || (arg2 == NULL)) {
5058 if (arg1 != NULL)
5059 xmlXPathFreeObject(arg1);
5060 else
5061 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005062 XP_ERROR0(XPATH_INVALID_OPERAND);
5063 }
5064
William M. Brack0c022ad2002-07-12 00:56:01 +00005065 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5066 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5067 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5068 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005069 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005070 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005071 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005072 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5073 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005074 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005075 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5076 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005077 }
5078 }
5079 return(ret);
5080 }
5081
5082 if (arg1->type != XPATH_NUMBER) {
5083 valuePush(ctxt, arg1);
5084 xmlXPathNumberFunction(ctxt, 1);
5085 arg1 = valuePop(ctxt);
5086 }
5087 if (arg1->type != XPATH_NUMBER) {
5088 xmlXPathFreeObject(arg1);
5089 xmlXPathFreeObject(arg2);
5090 XP_ERROR0(XPATH_INVALID_OPERAND);
5091 }
5092 if (arg2->type != XPATH_NUMBER) {
5093 valuePush(ctxt, arg2);
5094 xmlXPathNumberFunction(ctxt, 1);
5095 arg2 = valuePop(ctxt);
5096 }
5097 if (arg2->type != XPATH_NUMBER) {
5098 xmlXPathFreeObject(arg1);
5099 xmlXPathFreeObject(arg2);
5100 XP_ERROR0(XPATH_INVALID_OPERAND);
5101 }
5102 /*
5103 * Add tests for infinity and nan
5104 * => feedback on 3.4 for Inf and NaN
5105 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005106 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005107 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005108 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005109 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005110 arg1i=xmlXPathIsInf(arg1->floatval);
5111 arg2i=xmlXPathIsInf(arg2->floatval);
5112 if (inf && strict) {
5113 if ((arg1i == -1 && arg2i != -1) ||
5114 (arg2i == 1 && arg1i != 1)) {
5115 ret = 1;
5116 } else if (arg1i == 0 && arg2i == 0) {
5117 ret = (arg1->floatval < arg2->floatval);
5118 } else {
5119 ret = 0;
5120 }
5121 }
5122 else if (inf && !strict) {
5123 if (arg1i == -1 || arg2i == 1) {
5124 ret = 1;
5125 } else if (arg1i == 0 && arg2i == 0) {
5126 ret = (arg1->floatval <= arg2->floatval);
5127 } else {
5128 ret = 0;
5129 }
5130 }
5131 else if (!inf && strict) {
5132 if ((arg1i == 1 && arg2i != 1) ||
5133 (arg2i == -1 && arg1i != -1)) {
5134 ret = 1;
5135 } else if (arg1i == 0 && arg2i == 0) {
5136 ret = (arg1->floatval > arg2->floatval);
5137 } else {
5138 ret = 0;
5139 }
5140 }
5141 else if (!inf && !strict) {
5142 if (arg1i == 1 || arg2i == -1) {
5143 ret = 1;
5144 } else if (arg1i == 0 && arg2i == 0) {
5145 ret = (arg1->floatval >= arg2->floatval);
5146 } else {
5147 ret = 0;
5148 }
5149 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005150 }
Owen Taylor3473f882001-02-23 17:55:21 +00005151 xmlXPathFreeObject(arg1);
5152 xmlXPathFreeObject(arg2);
5153 return(ret);
5154}
5155
5156/**
5157 * xmlXPathValueFlipSign:
5158 * @ctxt: the XPath Parser context
5159 *
5160 * Implement the unary - operation on an XPath object
5161 * The numeric operators convert their operands to numbers as if
5162 * by calling the number function.
5163 */
5164void
5165xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005166 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005167 CAST_TO_NUMBER;
5168 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005169 if (xmlXPathIsNaN(ctxt->value->floatval))
5170 ctxt->value->floatval=xmlXPathNAN;
5171 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5172 ctxt->value->floatval=xmlXPathNINF;
5173 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5174 ctxt->value->floatval=xmlXPathPINF;
5175 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005176 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5177 ctxt->value->floatval = xmlXPathNZERO;
5178 else
5179 ctxt->value->floatval = 0;
5180 }
5181 else
5182 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005183}
5184
5185/**
5186 * xmlXPathAddValues:
5187 * @ctxt: the XPath Parser context
5188 *
5189 * Implement the add operation on XPath objects:
5190 * The numeric operators convert their operands to numbers as if
5191 * by calling the number function.
5192 */
5193void
5194xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5195 xmlXPathObjectPtr arg;
5196 double val;
5197
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005198 arg = valuePop(ctxt);
5199 if (arg == NULL)
5200 XP_ERROR(XPATH_INVALID_OPERAND);
5201 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005202 xmlXPathFreeObject(arg);
5203
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005204 CAST_TO_NUMBER;
5205 CHECK_TYPE(XPATH_NUMBER);
5206 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005207}
5208
5209/**
5210 * xmlXPathSubValues:
5211 * @ctxt: the XPath Parser context
5212 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005213 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005214 * The numeric operators convert their operands to numbers as if
5215 * by calling the number function.
5216 */
5217void
5218xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5219 xmlXPathObjectPtr arg;
5220 double val;
5221
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005222 arg = valuePop(ctxt);
5223 if (arg == NULL)
5224 XP_ERROR(XPATH_INVALID_OPERAND);
5225 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005226 xmlXPathFreeObject(arg);
5227
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005228 CAST_TO_NUMBER;
5229 CHECK_TYPE(XPATH_NUMBER);
5230 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005231}
5232
5233/**
5234 * xmlXPathMultValues:
5235 * @ctxt: the XPath Parser context
5236 *
5237 * Implement the multiply operation on XPath objects:
5238 * The numeric operators convert their operands to numbers as if
5239 * by calling the number function.
5240 */
5241void
5242xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5243 xmlXPathObjectPtr arg;
5244 double val;
5245
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005246 arg = valuePop(ctxt);
5247 if (arg == NULL)
5248 XP_ERROR(XPATH_INVALID_OPERAND);
5249 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005250 xmlXPathFreeObject(arg);
5251
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005252 CAST_TO_NUMBER;
5253 CHECK_TYPE(XPATH_NUMBER);
5254 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005255}
5256
5257/**
5258 * xmlXPathDivValues:
5259 * @ctxt: the XPath Parser context
5260 *
5261 * Implement the div operation on XPath objects @arg1 / @arg2:
5262 * The numeric operators convert their operands to numbers as if
5263 * by calling the number function.
5264 */
5265void
5266xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5267 xmlXPathObjectPtr arg;
5268 double val;
5269
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005270 arg = valuePop(ctxt);
5271 if (arg == NULL)
5272 XP_ERROR(XPATH_INVALID_OPERAND);
5273 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005274 xmlXPathFreeObject(arg);
5275
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005276 CAST_TO_NUMBER;
5277 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005278 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5279 ctxt->value->floatval = xmlXPathNAN;
5280 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005281 if (ctxt->value->floatval == 0)
5282 ctxt->value->floatval = xmlXPathNAN;
5283 else if (ctxt->value->floatval > 0)
5284 ctxt->value->floatval = xmlXPathNINF;
5285 else if (ctxt->value->floatval < 0)
5286 ctxt->value->floatval = xmlXPathPINF;
5287 }
5288 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005289 if (ctxt->value->floatval == 0)
5290 ctxt->value->floatval = xmlXPathNAN;
5291 else if (ctxt->value->floatval > 0)
5292 ctxt->value->floatval = xmlXPathPINF;
5293 else if (ctxt->value->floatval < 0)
5294 ctxt->value->floatval = xmlXPathNINF;
5295 } else
5296 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005297}
5298
5299/**
5300 * xmlXPathModValues:
5301 * @ctxt: the XPath Parser context
5302 *
5303 * Implement the mod operation on XPath objects: @arg1 / @arg2
5304 * The numeric operators convert their operands to numbers as if
5305 * by calling the number function.
5306 */
5307void
5308xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5309 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005310 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005311
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005312 arg = valuePop(ctxt);
5313 if (arg == NULL)
5314 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005315 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005316 xmlXPathFreeObject(arg);
5317
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005318 CAST_TO_NUMBER;
5319 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005320 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005321 if (arg2 == 0)
5322 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005323 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005324 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005325 }
Owen Taylor3473f882001-02-23 17:55:21 +00005326}
5327
5328/************************************************************************
5329 * *
5330 * The traversal functions *
5331 * *
5332 ************************************************************************/
5333
Owen Taylor3473f882001-02-23 17:55:21 +00005334/*
5335 * A traversal function enumerates nodes along an axis.
5336 * Initially it must be called with NULL, and it indicates
5337 * termination on the axis by returning NULL.
5338 */
5339typedef xmlNodePtr (*xmlXPathTraversalFunction)
5340 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5341
5342/**
5343 * xmlXPathNextSelf:
5344 * @ctxt: the XPath Parser context
5345 * @cur: the current node in the traversal
5346 *
5347 * Traversal function for the "self" direction
5348 * The self axis contains just the context node itself
5349 *
5350 * Returns the next element following that axis
5351 */
5352xmlNodePtr
5353xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005354 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005355 if (cur == NULL)
5356 return(ctxt->context->node);
5357 return(NULL);
5358}
5359
5360/**
5361 * xmlXPathNextChild:
5362 * @ctxt: the XPath Parser context
5363 * @cur: the current node in the traversal
5364 *
5365 * Traversal function for the "child" direction
5366 * The child axis contains the children of the context node in document order.
5367 *
5368 * Returns the next element following that axis
5369 */
5370xmlNodePtr
5371xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005372 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005373 if (cur == NULL) {
5374 if (ctxt->context->node == NULL) return(NULL);
5375 switch (ctxt->context->node->type) {
5376 case XML_ELEMENT_NODE:
5377 case XML_TEXT_NODE:
5378 case XML_CDATA_SECTION_NODE:
5379 case XML_ENTITY_REF_NODE:
5380 case XML_ENTITY_NODE:
5381 case XML_PI_NODE:
5382 case XML_COMMENT_NODE:
5383 case XML_NOTATION_NODE:
5384 case XML_DTD_NODE:
5385 return(ctxt->context->node->children);
5386 case XML_DOCUMENT_NODE:
5387 case XML_DOCUMENT_TYPE_NODE:
5388 case XML_DOCUMENT_FRAG_NODE:
5389 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005390#ifdef LIBXML_DOCB_ENABLED
5391 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005392#endif
5393 return(((xmlDocPtr) ctxt->context->node)->children);
5394 case XML_ELEMENT_DECL:
5395 case XML_ATTRIBUTE_DECL:
5396 case XML_ENTITY_DECL:
5397 case XML_ATTRIBUTE_NODE:
5398 case XML_NAMESPACE_DECL:
5399 case XML_XINCLUDE_START:
5400 case XML_XINCLUDE_END:
5401 return(NULL);
5402 }
5403 return(NULL);
5404 }
5405 if ((cur->type == XML_DOCUMENT_NODE) ||
5406 (cur->type == XML_HTML_DOCUMENT_NODE))
5407 return(NULL);
5408 return(cur->next);
5409}
5410
5411/**
5412 * xmlXPathNextDescendant:
5413 * @ctxt: the XPath Parser context
5414 * @cur: the current node in the traversal
5415 *
5416 * Traversal function for the "descendant" direction
5417 * the descendant axis contains the descendants of the context node in document
5418 * order; a descendant is a child or a child of a child and so on.
5419 *
5420 * Returns the next element following that axis
5421 */
5422xmlNodePtr
5423xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005424 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005425 if (cur == NULL) {
5426 if (ctxt->context->node == NULL)
5427 return(NULL);
5428 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5429 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5430 return(NULL);
5431
5432 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5433 return(ctxt->context->doc->children);
5434 return(ctxt->context->node->children);
5435 }
5436
Daniel Veillard567e1b42001-08-01 15:53:47 +00005437 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005438 /*
5439 * Do not descend on entities declarations
5440 */
5441 if (cur->children->type != XML_ENTITY_DECL) {
5442 cur = cur->children;
5443 /*
5444 * Skip DTDs
5445 */
5446 if (cur->type != XML_DTD_NODE)
5447 return(cur);
5448 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005449 }
5450
5451 if (cur == ctxt->context->node) return(NULL);
5452
Daniel Veillard68e9e742002-11-16 15:35:11 +00005453 while (cur->next != NULL) {
5454 cur = cur->next;
5455 if ((cur->type != XML_ENTITY_DECL) &&
5456 (cur->type != XML_DTD_NODE))
5457 return(cur);
5458 }
Owen Taylor3473f882001-02-23 17:55:21 +00005459
5460 do {
5461 cur = cur->parent;
5462 if (cur == NULL) return(NULL);
5463 if (cur == ctxt->context->node) return(NULL);
5464 if (cur->next != NULL) {
5465 cur = cur->next;
5466 return(cur);
5467 }
5468 } while (cur != NULL);
5469 return(cur);
5470}
5471
5472/**
5473 * xmlXPathNextDescendantOrSelf:
5474 * @ctxt: the XPath Parser context
5475 * @cur: the current node in the traversal
5476 *
5477 * Traversal function for the "descendant-or-self" direction
5478 * the descendant-or-self axis contains the context node and the descendants
5479 * of the context node in document order; thus the context node is the first
5480 * node on the axis, and the first child of the context node is the second node
5481 * on the axis
5482 *
5483 * Returns the next element following that axis
5484 */
5485xmlNodePtr
5486xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005487 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005488 if (cur == NULL) {
5489 if (ctxt->context->node == NULL)
5490 return(NULL);
5491 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5492 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5493 return(NULL);
5494 return(ctxt->context->node);
5495 }
5496
5497 return(xmlXPathNextDescendant(ctxt, cur));
5498}
5499
5500/**
5501 * xmlXPathNextParent:
5502 * @ctxt: the XPath Parser context
5503 * @cur: the current node in the traversal
5504 *
5505 * Traversal function for the "parent" direction
5506 * The parent axis contains the parent of the context node, if there is one.
5507 *
5508 * Returns the next element following that axis
5509 */
5510xmlNodePtr
5511xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005512 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005513 /*
5514 * the parent of an attribute or namespace node is the element
5515 * to which the attribute or namespace node is attached
5516 * Namespace handling !!!
5517 */
5518 if (cur == NULL) {
5519 if (ctxt->context->node == NULL) return(NULL);
5520 switch (ctxt->context->node->type) {
5521 case XML_ELEMENT_NODE:
5522 case XML_TEXT_NODE:
5523 case XML_CDATA_SECTION_NODE:
5524 case XML_ENTITY_REF_NODE:
5525 case XML_ENTITY_NODE:
5526 case XML_PI_NODE:
5527 case XML_COMMENT_NODE:
5528 case XML_NOTATION_NODE:
5529 case XML_DTD_NODE:
5530 case XML_ELEMENT_DECL:
5531 case XML_ATTRIBUTE_DECL:
5532 case XML_XINCLUDE_START:
5533 case XML_XINCLUDE_END:
5534 case XML_ENTITY_DECL:
5535 if (ctxt->context->node->parent == NULL)
5536 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005537 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005538 ((ctxt->context->node->parent->name[0] == ' ') ||
5539 (xmlStrEqual(ctxt->context->node->parent->name,
5540 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005541 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005542 return(ctxt->context->node->parent);
5543 case XML_ATTRIBUTE_NODE: {
5544 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5545
5546 return(att->parent);
5547 }
5548 case XML_DOCUMENT_NODE:
5549 case XML_DOCUMENT_TYPE_NODE:
5550 case XML_DOCUMENT_FRAG_NODE:
5551 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005552#ifdef LIBXML_DOCB_ENABLED
5553 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005554#endif
5555 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005556 case XML_NAMESPACE_DECL: {
5557 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5558
5559 if ((ns->next != NULL) &&
5560 (ns->next->type != XML_NAMESPACE_DECL))
5561 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005562 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005563 }
Owen Taylor3473f882001-02-23 17:55:21 +00005564 }
5565 }
5566 return(NULL);
5567}
5568
5569/**
5570 * xmlXPathNextAncestor:
5571 * @ctxt: the XPath Parser context
5572 * @cur: the current node in the traversal
5573 *
5574 * Traversal function for the "ancestor" direction
5575 * the ancestor axis contains the ancestors of the context node; the ancestors
5576 * of the context node consist of the parent of context node and the parent's
5577 * parent and so on; the nodes are ordered in reverse document order; thus the
5578 * parent is the first node on the axis, and the parent's parent is the second
5579 * node on the axis
5580 *
5581 * Returns the next element following that axis
5582 */
5583xmlNodePtr
5584xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005585 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005586 /*
5587 * the parent of an attribute or namespace node is the element
5588 * to which the attribute or namespace node is attached
5589 * !!!!!!!!!!!!!
5590 */
5591 if (cur == NULL) {
5592 if (ctxt->context->node == NULL) return(NULL);
5593 switch (ctxt->context->node->type) {
5594 case XML_ELEMENT_NODE:
5595 case XML_TEXT_NODE:
5596 case XML_CDATA_SECTION_NODE:
5597 case XML_ENTITY_REF_NODE:
5598 case XML_ENTITY_NODE:
5599 case XML_PI_NODE:
5600 case XML_COMMENT_NODE:
5601 case XML_DTD_NODE:
5602 case XML_ELEMENT_DECL:
5603 case XML_ATTRIBUTE_DECL:
5604 case XML_ENTITY_DECL:
5605 case XML_NOTATION_NODE:
5606 case XML_XINCLUDE_START:
5607 case XML_XINCLUDE_END:
5608 if (ctxt->context->node->parent == NULL)
5609 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005610 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005611 ((ctxt->context->node->parent->name[0] == ' ') ||
5612 (xmlStrEqual(ctxt->context->node->parent->name,
5613 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005614 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005615 return(ctxt->context->node->parent);
5616 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005617 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005618
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005619 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005620 }
5621 case XML_DOCUMENT_NODE:
5622 case XML_DOCUMENT_TYPE_NODE:
5623 case XML_DOCUMENT_FRAG_NODE:
5624 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005625#ifdef LIBXML_DOCB_ENABLED
5626 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005627#endif
5628 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005629 case XML_NAMESPACE_DECL: {
5630 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5631
5632 if ((ns->next != NULL) &&
5633 (ns->next->type != XML_NAMESPACE_DECL))
5634 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005635 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005636 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005637 }
Owen Taylor3473f882001-02-23 17:55:21 +00005638 }
5639 return(NULL);
5640 }
5641 if (cur == ctxt->context->doc->children)
5642 return((xmlNodePtr) ctxt->context->doc);
5643 if (cur == (xmlNodePtr) ctxt->context->doc)
5644 return(NULL);
5645 switch (cur->type) {
5646 case XML_ELEMENT_NODE:
5647 case XML_TEXT_NODE:
5648 case XML_CDATA_SECTION_NODE:
5649 case XML_ENTITY_REF_NODE:
5650 case XML_ENTITY_NODE:
5651 case XML_PI_NODE:
5652 case XML_COMMENT_NODE:
5653 case XML_NOTATION_NODE:
5654 case XML_DTD_NODE:
5655 case XML_ELEMENT_DECL:
5656 case XML_ATTRIBUTE_DECL:
5657 case XML_ENTITY_DECL:
5658 case XML_XINCLUDE_START:
5659 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005660 if (cur->parent == NULL)
5661 return(NULL);
5662 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005663 ((cur->parent->name[0] == ' ') ||
5664 (xmlStrEqual(cur->parent->name,
5665 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005666 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005667 return(cur->parent);
5668 case XML_ATTRIBUTE_NODE: {
5669 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5670
5671 return(att->parent);
5672 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005673 case XML_NAMESPACE_DECL: {
5674 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5675
5676 if ((ns->next != NULL) &&
5677 (ns->next->type != XML_NAMESPACE_DECL))
5678 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005679 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005680 return(NULL);
5681 }
Owen Taylor3473f882001-02-23 17:55:21 +00005682 case XML_DOCUMENT_NODE:
5683 case XML_DOCUMENT_TYPE_NODE:
5684 case XML_DOCUMENT_FRAG_NODE:
5685 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005686#ifdef LIBXML_DOCB_ENABLED
5687 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005688#endif
5689 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005690 }
5691 return(NULL);
5692}
5693
5694/**
5695 * xmlXPathNextAncestorOrSelf:
5696 * @ctxt: the XPath Parser context
5697 * @cur: the current node in the traversal
5698 *
5699 * Traversal function for the "ancestor-or-self" direction
5700 * he ancestor-or-self axis contains the context node and ancestors of
5701 * the context node in reverse document order; thus the context node is
5702 * the first node on the axis, and the context node's parent the second;
5703 * parent here is defined the same as with the parent axis.
5704 *
5705 * Returns the next element following that axis
5706 */
5707xmlNodePtr
5708xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005709 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005710 if (cur == NULL)
5711 return(ctxt->context->node);
5712 return(xmlXPathNextAncestor(ctxt, cur));
5713}
5714
5715/**
5716 * xmlXPathNextFollowingSibling:
5717 * @ctxt: the XPath Parser context
5718 * @cur: the current node in the traversal
5719 *
5720 * Traversal function for the "following-sibling" direction
5721 * The following-sibling axis contains the following siblings of the context
5722 * node in document order.
5723 *
5724 * Returns the next element following that axis
5725 */
5726xmlNodePtr
5727xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005728 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005729 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5730 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5731 return(NULL);
5732 if (cur == (xmlNodePtr) ctxt->context->doc)
5733 return(NULL);
5734 if (cur == NULL)
5735 return(ctxt->context->node->next);
5736 return(cur->next);
5737}
5738
5739/**
5740 * xmlXPathNextPrecedingSibling:
5741 * @ctxt: the XPath Parser context
5742 * @cur: the current node in the traversal
5743 *
5744 * Traversal function for the "preceding-sibling" direction
5745 * The preceding-sibling axis contains the preceding siblings of the context
5746 * node in reverse document order; the first preceding sibling is first on the
5747 * axis; the sibling preceding that node is the second on the axis and so on.
5748 *
5749 * Returns the next element following that axis
5750 */
5751xmlNodePtr
5752xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005753 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005754 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5755 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5756 return(NULL);
5757 if (cur == (xmlNodePtr) ctxt->context->doc)
5758 return(NULL);
5759 if (cur == NULL)
5760 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005761 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5762 cur = cur->prev;
5763 if (cur == NULL)
5764 return(ctxt->context->node->prev);
5765 }
Owen Taylor3473f882001-02-23 17:55:21 +00005766 return(cur->prev);
5767}
5768
5769/**
5770 * xmlXPathNextFollowing:
5771 * @ctxt: the XPath Parser context
5772 * @cur: the current node in the traversal
5773 *
5774 * Traversal function for the "following" direction
5775 * The following axis contains all nodes in the same document as the context
5776 * node that are after the context node in document order, excluding any
5777 * descendants and excluding attribute nodes and namespace nodes; the nodes
5778 * are ordered in document order
5779 *
5780 * Returns the next element following that axis
5781 */
5782xmlNodePtr
5783xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005784 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005785 if (cur != NULL && cur->children != NULL)
5786 return cur->children ;
5787 if (cur == NULL) cur = ctxt->context->node;
5788 if (cur == NULL) return(NULL) ; /* ERROR */
5789 if (cur->next != NULL) return(cur->next) ;
5790 do {
5791 cur = cur->parent;
5792 if (cur == NULL) return(NULL);
5793 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5794 if (cur->next != NULL) return(cur->next);
5795 } while (cur != NULL);
5796 return(cur);
5797}
5798
5799/*
5800 * xmlXPathIsAncestor:
5801 * @ancestor: the ancestor node
5802 * @node: the current node
5803 *
5804 * Check that @ancestor is a @node's ancestor
5805 *
5806 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5807 */
5808static int
5809xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5810 if ((ancestor == NULL) || (node == NULL)) return(0);
5811 /* nodes need to be in the same document */
5812 if (ancestor->doc != node->doc) return(0);
5813 /* avoid searching if ancestor or node is the root node */
5814 if (ancestor == (xmlNodePtr) node->doc) return(1);
5815 if (node == (xmlNodePtr) ancestor->doc) return(0);
5816 while (node->parent != NULL) {
5817 if (node->parent == ancestor)
5818 return(1);
5819 node = node->parent;
5820 }
5821 return(0);
5822}
5823
5824/**
5825 * xmlXPathNextPreceding:
5826 * @ctxt: the XPath Parser context
5827 * @cur: the current node in the traversal
5828 *
5829 * Traversal function for the "preceding" direction
5830 * the preceding axis contains all nodes in the same document as the context
5831 * node that are before the context node in document order, excluding any
5832 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5833 * ordered in reverse document order
5834 *
5835 * Returns the next element following that axis
5836 */
5837xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005838xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5839{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005840 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005841 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005842 cur = ctxt->context->node;
5843 if (cur == NULL)
5844 return (NULL);
5845 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5846 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005847 do {
5848 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005849 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5850 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005851 }
5852
5853 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005854 if (cur == NULL)
5855 return (NULL);
5856 if (cur == ctxt->context->doc->children)
5857 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005858 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005859 return (cur);
5860}
5861
5862/**
5863 * xmlXPathNextPrecedingInternal:
5864 * @ctxt: the XPath Parser context
5865 * @cur: the current node in the traversal
5866 *
5867 * Traversal function for the "preceding" direction
5868 * the preceding axis contains all nodes in the same document as the context
5869 * node that are before the context node in document order, excluding any
5870 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5871 * ordered in reverse document order
5872 * This is a faster implementation but internal only since it requires a
5873 * state kept in the parser context: ctxt->ancestor.
5874 *
5875 * Returns the next element following that axis
5876 */
5877static xmlNodePtr
5878xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5879 xmlNodePtr cur)
5880{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005881 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005882 if (cur == NULL) {
5883 cur = ctxt->context->node;
5884 if (cur == NULL)
5885 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005886 if (cur->type == XML_NAMESPACE_DECL)
5887 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005888 ctxt->ancestor = cur->parent;
5889 }
5890 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5891 cur = cur->prev;
5892 while (cur->prev == NULL) {
5893 cur = cur->parent;
5894 if (cur == NULL)
5895 return (NULL);
5896 if (cur == ctxt->context->doc->children)
5897 return (NULL);
5898 if (cur != ctxt->ancestor)
5899 return (cur);
5900 ctxt->ancestor = cur->parent;
5901 }
5902 cur = cur->prev;
5903 while (cur->last != NULL)
5904 cur = cur->last;
5905 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005906}
5907
5908/**
5909 * xmlXPathNextNamespace:
5910 * @ctxt: the XPath Parser context
5911 * @cur: the current attribute in the traversal
5912 *
5913 * Traversal function for the "namespace" direction
5914 * the namespace axis contains the namespace nodes of the context node;
5915 * the order of nodes on this axis is implementation-defined; the axis will
5916 * be empty unless the context node is an element
5917 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005918 * We keep the XML namespace node at the end of the list.
5919 *
Owen Taylor3473f882001-02-23 17:55:21 +00005920 * Returns the next element following that axis
5921 */
5922xmlNodePtr
5923xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005924 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005925 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005926 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005927 if (ctxt->context->tmpNsList != NULL)
5928 xmlFree(ctxt->context->tmpNsList);
5929 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005930 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005931 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005932 if (ctxt->context->tmpNsList != NULL) {
5933 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5934 ctxt->context->tmpNsNr++;
5935 }
5936 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005937 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005938 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005939 if (ctxt->context->tmpNsNr > 0) {
5940 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5941 } else {
5942 if (ctxt->context->tmpNsList != NULL)
5943 xmlFree(ctxt->context->tmpNsList);
5944 ctxt->context->tmpNsList = NULL;
5945 return(NULL);
5946 }
Owen Taylor3473f882001-02-23 17:55:21 +00005947}
5948
5949/**
5950 * xmlXPathNextAttribute:
5951 * @ctxt: the XPath Parser context
5952 * @cur: the current attribute in the traversal
5953 *
5954 * Traversal function for the "attribute" direction
5955 * TODO: support DTD inherited default attributes
5956 *
5957 * Returns the next element following that axis
5958 */
5959xmlNodePtr
5960xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005961 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00005962 if (ctxt->context->node == NULL)
5963 return(NULL);
5964 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5965 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005966 if (cur == NULL) {
5967 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5968 return(NULL);
5969 return((xmlNodePtr)ctxt->context->node->properties);
5970 }
5971 return((xmlNodePtr)cur->next);
5972}
5973
5974/************************************************************************
5975 * *
5976 * NodeTest Functions *
5977 * *
5978 ************************************************************************/
5979
Owen Taylor3473f882001-02-23 17:55:21 +00005980#define IS_FUNCTION 200
5981
Owen Taylor3473f882001-02-23 17:55:21 +00005982
5983/************************************************************************
5984 * *
5985 * Implicit tree core function library *
5986 * *
5987 ************************************************************************/
5988
5989/**
5990 * xmlXPathRoot:
5991 * @ctxt: the XPath Parser context
5992 *
5993 * Initialize the context to the root of the document
5994 */
5995void
5996xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005997 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00005998 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5999 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6000}
6001
6002/************************************************************************
6003 * *
6004 * The explicit core function library *
6005 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
6006 * *
6007 ************************************************************************/
6008
6009
6010/**
6011 * xmlXPathLastFunction:
6012 * @ctxt: the XPath Parser context
6013 * @nargs: the number of arguments
6014 *
6015 * Implement the last() XPath function
6016 * number last()
6017 * The last function returns the number of nodes in the context node list.
6018 */
6019void
6020xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6021 CHECK_ARITY(0);
6022 if (ctxt->context->contextSize >= 0) {
6023 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
6024#ifdef DEBUG_EXPR
6025 xmlGenericError(xmlGenericErrorContext,
6026 "last() : %d\n", ctxt->context->contextSize);
6027#endif
6028 } else {
6029 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6030 }
6031}
6032
6033/**
6034 * xmlXPathPositionFunction:
6035 * @ctxt: the XPath Parser context
6036 * @nargs: the number of arguments
6037 *
6038 * Implement the position() XPath function
6039 * number position()
6040 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006041 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00006042 * will be equal to last().
6043 */
6044void
6045xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6046 CHECK_ARITY(0);
6047 if (ctxt->context->proximityPosition >= 0) {
6048 valuePush(ctxt,
6049 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6050#ifdef DEBUG_EXPR
6051 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6052 ctxt->context->proximityPosition);
6053#endif
6054 } else {
6055 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6056 }
6057}
6058
6059/**
6060 * xmlXPathCountFunction:
6061 * @ctxt: the XPath Parser context
6062 * @nargs: the number of arguments
6063 *
6064 * Implement the count() XPath function
6065 * number count(node-set)
6066 */
6067void
6068xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6069 xmlXPathObjectPtr cur;
6070
6071 CHECK_ARITY(1);
6072 if ((ctxt->value == NULL) ||
6073 ((ctxt->value->type != XPATH_NODESET) &&
6074 (ctxt->value->type != XPATH_XSLT_TREE)))
6075 XP_ERROR(XPATH_INVALID_TYPE);
6076 cur = valuePop(ctxt);
6077
Daniel Veillard911f49a2001-04-07 15:39:35 +00006078 if ((cur == NULL) || (cur->nodesetval == NULL))
6079 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006080 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006081 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006082 } else {
6083 if ((cur->nodesetval->nodeNr != 1) ||
6084 (cur->nodesetval->nodeTab == NULL)) {
6085 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6086 } else {
6087 xmlNodePtr tmp;
6088 int i = 0;
6089
6090 tmp = cur->nodesetval->nodeTab[0];
6091 if (tmp != NULL) {
6092 tmp = tmp->children;
6093 while (tmp != NULL) {
6094 tmp = tmp->next;
6095 i++;
6096 }
6097 }
6098 valuePush(ctxt, xmlXPathNewFloat((double) i));
6099 }
6100 }
Owen Taylor3473f882001-02-23 17:55:21 +00006101 xmlXPathFreeObject(cur);
6102}
6103
6104/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006105 * xmlXPathGetElementsByIds:
6106 * @doc: the document
6107 * @ids: a whitespace separated list of IDs
6108 *
6109 * Selects elements by their unique ID.
6110 *
6111 * Returns a node-set of selected elements.
6112 */
6113static xmlNodeSetPtr
6114xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6115 xmlNodeSetPtr ret;
6116 const xmlChar *cur = ids;
6117 xmlChar *ID;
6118 xmlAttrPtr attr;
6119 xmlNodePtr elem = NULL;
6120
Daniel Veillard7a985a12003-07-06 17:57:42 +00006121 if (ids == NULL) return(NULL);
6122
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006123 ret = xmlXPathNodeSetCreate(NULL);
6124
William M. Brack76e95df2003-10-18 16:20:14 +00006125 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006126 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006127 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006128 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006129
6130 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006131 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00006132 /*
6133 * We used to check the fact that the value passed
6134 * was an NCName, but this generated much troubles for
6135 * me and Aleksey Sanin, people blatantly violated that
6136 * constaint, like Visa3D spec.
6137 * if (xmlValidateNCName(ID, 1) == 0)
6138 */
6139 attr = xmlGetID(doc, ID);
6140 if (attr != NULL) {
6141 if (attr->type == XML_ATTRIBUTE_NODE)
6142 elem = attr->parent;
6143 else if (attr->type == XML_ELEMENT_NODE)
6144 elem = (xmlNodePtr) attr;
6145 else
6146 elem = NULL;
6147 if (elem != NULL)
6148 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00006149 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006150 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006151 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006152
William M. Brack76e95df2003-10-18 16:20:14 +00006153 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006154 ids = cur;
6155 }
6156 return(ret);
6157}
6158
6159/**
Owen Taylor3473f882001-02-23 17:55:21 +00006160 * xmlXPathIdFunction:
6161 * @ctxt: the XPath Parser context
6162 * @nargs: the number of arguments
6163 *
6164 * Implement the id() XPath function
6165 * node-set id(object)
6166 * The id function selects elements by their unique ID
6167 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6168 * then the result is the union of the result of applying id to the
6169 * string value of each of the nodes in the argument node-set. When the
6170 * argument to id is of any other type, the argument is converted to a
6171 * string as if by a call to the string function; the string is split
6172 * into a whitespace-separated list of tokens (whitespace is any sequence
6173 * of characters matching the production S); the result is a node-set
6174 * containing the elements in the same document as the context node that
6175 * have a unique ID equal to any of the tokens in the list.
6176 */
6177void
6178xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006179 xmlChar *tokens;
6180 xmlNodeSetPtr ret;
6181 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006182
6183 CHECK_ARITY(1);
6184 obj = valuePop(ctxt);
6185 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006186 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006187 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006188 int i;
6189
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006190 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006191
Daniel Veillard911f49a2001-04-07 15:39:35 +00006192 if (obj->nodesetval != NULL) {
6193 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006194 tokens =
6195 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6196 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6197 ret = xmlXPathNodeSetMerge(ret, ns);
6198 xmlXPathFreeNodeSet(ns);
6199 if (tokens != NULL)
6200 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006201 }
Owen Taylor3473f882001-02-23 17:55:21 +00006202 }
6203
6204 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006205 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006206 return;
6207 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006208 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006209
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006210 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6211 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006212
Owen Taylor3473f882001-02-23 17:55:21 +00006213 xmlXPathFreeObject(obj);
6214 return;
6215}
6216
6217/**
6218 * xmlXPathLocalNameFunction:
6219 * @ctxt: the XPath Parser context
6220 * @nargs: the number of arguments
6221 *
6222 * Implement the local-name() XPath function
6223 * string local-name(node-set?)
6224 * The local-name function returns a string containing the local part
6225 * of the name of the node in the argument node-set that is first in
6226 * document order. If the node-set is empty or the first node has no
6227 * name, an empty string is returned. If the argument is omitted it
6228 * defaults to the context node.
6229 */
6230void
6231xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6232 xmlXPathObjectPtr cur;
6233
Daniel Veillarda82b1822004-11-08 16:24:57 +00006234 if (ctxt == NULL) return;
6235
Owen Taylor3473f882001-02-23 17:55:21 +00006236 if (nargs == 0) {
6237 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6238 nargs = 1;
6239 }
6240
6241 CHECK_ARITY(1);
6242 if ((ctxt->value == NULL) ||
6243 ((ctxt->value->type != XPATH_NODESET) &&
6244 (ctxt->value->type != XPATH_XSLT_TREE)))
6245 XP_ERROR(XPATH_INVALID_TYPE);
6246 cur = valuePop(ctxt);
6247
Daniel Veillard911f49a2001-04-07 15:39:35 +00006248 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006249 valuePush(ctxt, xmlXPathNewCString(""));
6250 } else {
6251 int i = 0; /* Should be first in document order !!!!! */
6252 switch (cur->nodesetval->nodeTab[i]->type) {
6253 case XML_ELEMENT_NODE:
6254 case XML_ATTRIBUTE_NODE:
6255 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006256 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6257 valuePush(ctxt, xmlXPathNewCString(""));
6258 else
6259 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006260 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6261 break;
6262 case XML_NAMESPACE_DECL:
6263 valuePush(ctxt, xmlXPathNewString(
6264 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6265 break;
6266 default:
6267 valuePush(ctxt, xmlXPathNewCString(""));
6268 }
6269 }
6270 xmlXPathFreeObject(cur);
6271}
6272
6273/**
6274 * xmlXPathNamespaceURIFunction:
6275 * @ctxt: the XPath Parser context
6276 * @nargs: the number of arguments
6277 *
6278 * Implement the namespace-uri() XPath function
6279 * string namespace-uri(node-set?)
6280 * The namespace-uri function returns a string containing the
6281 * namespace URI of the expanded name of the node in the argument
6282 * node-set that is first in document order. If the node-set is empty,
6283 * the first node has no name, or the expanded name has no namespace
6284 * URI, an empty string is returned. If the argument is omitted it
6285 * defaults to the context node.
6286 */
6287void
6288xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6289 xmlXPathObjectPtr cur;
6290
Daniel Veillarda82b1822004-11-08 16:24:57 +00006291 if (ctxt == NULL) return;
6292
Owen Taylor3473f882001-02-23 17:55:21 +00006293 if (nargs == 0) {
6294 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6295 nargs = 1;
6296 }
6297 CHECK_ARITY(1);
6298 if ((ctxt->value == NULL) ||
6299 ((ctxt->value->type != XPATH_NODESET) &&
6300 (ctxt->value->type != XPATH_XSLT_TREE)))
6301 XP_ERROR(XPATH_INVALID_TYPE);
6302 cur = valuePop(ctxt);
6303
Daniel Veillard911f49a2001-04-07 15:39:35 +00006304 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006305 valuePush(ctxt, xmlXPathNewCString(""));
6306 } else {
6307 int i = 0; /* Should be first in document order !!!!! */
6308 switch (cur->nodesetval->nodeTab[i]->type) {
6309 case XML_ELEMENT_NODE:
6310 case XML_ATTRIBUTE_NODE:
6311 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6312 valuePush(ctxt, xmlXPathNewCString(""));
6313 else
6314 valuePush(ctxt, xmlXPathNewString(
6315 cur->nodesetval->nodeTab[i]->ns->href));
6316 break;
6317 default:
6318 valuePush(ctxt, xmlXPathNewCString(""));
6319 }
6320 }
6321 xmlXPathFreeObject(cur);
6322}
6323
6324/**
6325 * xmlXPathNameFunction:
6326 * @ctxt: the XPath Parser context
6327 * @nargs: the number of arguments
6328 *
6329 * Implement the name() XPath function
6330 * string name(node-set?)
6331 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006332 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006333 * order. The QName must represent the name with respect to the namespace
6334 * declarations in effect on the node whose name is being represented.
6335 * Typically, this will be the form in which the name occurred in the XML
6336 * source. This need not be the case if there are namespace declarations
6337 * in effect on the node that associate multiple prefixes with the same
6338 * namespace. However, an implementation may include information about
6339 * the original prefix in its representation of nodes; in this case, an
6340 * implementation can ensure that the returned string is always the same
6341 * as the QName used in the XML source. If the argument it omitted it
6342 * defaults to the context node.
6343 * Libxml keep the original prefix so the "real qualified name" used is
6344 * returned.
6345 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006346static void
Daniel Veillard04383752001-07-08 14:27:15 +00006347xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6348{
Owen Taylor3473f882001-02-23 17:55:21 +00006349 xmlXPathObjectPtr cur;
6350
6351 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006352 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6353 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006354 }
6355
6356 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006357 if ((ctxt->value == NULL) ||
6358 ((ctxt->value->type != XPATH_NODESET) &&
6359 (ctxt->value->type != XPATH_XSLT_TREE)))
6360 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006361 cur = valuePop(ctxt);
6362
Daniel Veillard911f49a2001-04-07 15:39:35 +00006363 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006364 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006365 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006366 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006367
Daniel Veillard04383752001-07-08 14:27:15 +00006368 switch (cur->nodesetval->nodeTab[i]->type) {
6369 case XML_ELEMENT_NODE:
6370 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006371 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6372 valuePush(ctxt, xmlXPathNewCString(""));
6373 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6374 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006375 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006376 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006377
Daniel Veillard652d8a92003-02-04 19:28:49 +00006378 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006379 xmlChar *fullname;
6380
6381 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6382 cur->nodesetval->nodeTab[i]->ns->prefix,
6383 NULL, 0);
6384 if (fullname == cur->nodesetval->nodeTab[i]->name)
6385 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6386 if (fullname == NULL) {
6387 XP_ERROR(XPATH_MEMORY_ERROR);
6388 }
6389 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006390 }
6391 break;
6392 default:
6393 valuePush(ctxt,
6394 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6395 xmlXPathLocalNameFunction(ctxt, 1);
6396 }
Owen Taylor3473f882001-02-23 17:55:21 +00006397 }
6398 xmlXPathFreeObject(cur);
6399}
6400
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006401
6402/**
Owen Taylor3473f882001-02-23 17:55:21 +00006403 * xmlXPathStringFunction:
6404 * @ctxt: the XPath Parser context
6405 * @nargs: the number of arguments
6406 *
6407 * Implement the string() XPath function
6408 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006409 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006410 * - A node-set is converted to a string by returning the value of
6411 * the node in the node-set that is first in document order.
6412 * If the node-set is empty, an empty string is returned.
6413 * - A number is converted to a string as follows
6414 * + NaN is converted to the string NaN
6415 * + positive zero is converted to the string 0
6416 * + negative zero is converted to the string 0
6417 * + positive infinity is converted to the string Infinity
6418 * + negative infinity is converted to the string -Infinity
6419 * + if the number is an integer, the number is represented in
6420 * decimal form as a Number with no decimal point and no leading
6421 * zeros, preceded by a minus sign (-) if the number is negative
6422 * + otherwise, the number is represented in decimal form as a
6423 * Number including a decimal point with at least one digit
6424 * before the decimal point and at least one digit after the
6425 * decimal point, preceded by a minus sign (-) if the number
6426 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006427 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006428 * before the decimal point; beyond the one required digit
6429 * after the decimal point there must be as many, but only as
6430 * many, more digits as are needed to uniquely distinguish the
6431 * number from all other IEEE 754 numeric values.
6432 * - The boolean false value is converted to the string false.
6433 * The boolean true value is converted to the string true.
6434 *
6435 * If the argument is omitted, it defaults to a node-set with the
6436 * context node as its only member.
6437 */
6438void
6439xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6440 xmlXPathObjectPtr cur;
6441
Daniel Veillarda82b1822004-11-08 16:24:57 +00006442 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006443 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006444 valuePush(ctxt,
6445 xmlXPathWrapString(
6446 xmlXPathCastNodeToString(ctxt->context->node)));
6447 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006448 }
6449
6450 CHECK_ARITY(1);
6451 cur = valuePop(ctxt);
6452 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006453 cur = xmlXPathConvertString(cur);
6454 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006455}
6456
6457/**
6458 * xmlXPathStringLengthFunction:
6459 * @ctxt: the XPath Parser context
6460 * @nargs: the number of arguments
6461 *
6462 * Implement the string-length() XPath function
6463 * number string-length(string?)
6464 * The string-length returns the number of characters in the string
6465 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6466 * the context node converted to a string, in other words the value
6467 * of the context node.
6468 */
6469void
6470xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6471 xmlXPathObjectPtr cur;
6472
6473 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006474 if ((ctxt == NULL) || (ctxt->context == NULL))
6475 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006476 if (ctxt->context->node == NULL) {
6477 valuePush(ctxt, xmlXPathNewFloat(0));
6478 } else {
6479 xmlChar *content;
6480
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006481 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006482 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006483 xmlFree(content);
6484 }
6485 return;
6486 }
6487 CHECK_ARITY(1);
6488 CAST_TO_STRING;
6489 CHECK_TYPE(XPATH_STRING);
6490 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006491 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006492 xmlXPathFreeObject(cur);
6493}
6494
6495/**
6496 * xmlXPathConcatFunction:
6497 * @ctxt: the XPath Parser context
6498 * @nargs: the number of arguments
6499 *
6500 * Implement the concat() XPath function
6501 * string concat(string, string, string*)
6502 * The concat function returns the concatenation of its arguments.
6503 */
6504void
6505xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6506 xmlXPathObjectPtr cur, newobj;
6507 xmlChar *tmp;
6508
Daniel Veillarda82b1822004-11-08 16:24:57 +00006509 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006510 if (nargs < 2) {
6511 CHECK_ARITY(2);
6512 }
6513
6514 CAST_TO_STRING;
6515 cur = valuePop(ctxt);
6516 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6517 xmlXPathFreeObject(cur);
6518 return;
6519 }
6520 nargs--;
6521
6522 while (nargs > 0) {
6523 CAST_TO_STRING;
6524 newobj = valuePop(ctxt);
6525 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6526 xmlXPathFreeObject(newobj);
6527 xmlXPathFreeObject(cur);
6528 XP_ERROR(XPATH_INVALID_TYPE);
6529 }
6530 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6531 newobj->stringval = cur->stringval;
6532 cur->stringval = tmp;
6533
6534 xmlXPathFreeObject(newobj);
6535 nargs--;
6536 }
6537 valuePush(ctxt, cur);
6538}
6539
6540/**
6541 * xmlXPathContainsFunction:
6542 * @ctxt: the XPath Parser context
6543 * @nargs: the number of arguments
6544 *
6545 * Implement the contains() XPath function
6546 * boolean contains(string, string)
6547 * The contains function returns true if the first argument string
6548 * contains the second argument string, and otherwise returns false.
6549 */
6550void
6551xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6552 xmlXPathObjectPtr hay, needle;
6553
6554 CHECK_ARITY(2);
6555 CAST_TO_STRING;
6556 CHECK_TYPE(XPATH_STRING);
6557 needle = valuePop(ctxt);
6558 CAST_TO_STRING;
6559 hay = valuePop(ctxt);
6560 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6561 xmlXPathFreeObject(hay);
6562 xmlXPathFreeObject(needle);
6563 XP_ERROR(XPATH_INVALID_TYPE);
6564 }
6565 if (xmlStrstr(hay->stringval, needle->stringval))
6566 valuePush(ctxt, xmlXPathNewBoolean(1));
6567 else
6568 valuePush(ctxt, xmlXPathNewBoolean(0));
6569 xmlXPathFreeObject(hay);
6570 xmlXPathFreeObject(needle);
6571}
6572
6573/**
6574 * xmlXPathStartsWithFunction:
6575 * @ctxt: the XPath Parser context
6576 * @nargs: the number of arguments
6577 *
6578 * Implement the starts-with() XPath function
6579 * boolean starts-with(string, string)
6580 * The starts-with function returns true if the first argument string
6581 * starts with the second argument string, and otherwise returns false.
6582 */
6583void
6584xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6585 xmlXPathObjectPtr hay, needle;
6586 int n;
6587
6588 CHECK_ARITY(2);
6589 CAST_TO_STRING;
6590 CHECK_TYPE(XPATH_STRING);
6591 needle = valuePop(ctxt);
6592 CAST_TO_STRING;
6593 hay = valuePop(ctxt);
6594 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6595 xmlXPathFreeObject(hay);
6596 xmlXPathFreeObject(needle);
6597 XP_ERROR(XPATH_INVALID_TYPE);
6598 }
6599 n = xmlStrlen(needle->stringval);
6600 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6601 valuePush(ctxt, xmlXPathNewBoolean(0));
6602 else
6603 valuePush(ctxt, xmlXPathNewBoolean(1));
6604 xmlXPathFreeObject(hay);
6605 xmlXPathFreeObject(needle);
6606}
6607
6608/**
6609 * xmlXPathSubstringFunction:
6610 * @ctxt: the XPath Parser context
6611 * @nargs: the number of arguments
6612 *
6613 * Implement the substring() XPath function
6614 * string substring(string, number, number?)
6615 * The substring function returns the substring of the first argument
6616 * starting at the position specified in the second argument with
6617 * length specified in the third argument. For example,
6618 * substring("12345",2,3) returns "234". If the third argument is not
6619 * specified, it returns the substring starting at the position specified
6620 * in the second argument and continuing to the end of the string. For
6621 * example, substring("12345",2) returns "2345". More precisely, each
6622 * character in the string (see [3.6 Strings]) is considered to have a
6623 * numeric position: the position of the first character is 1, the position
6624 * of the second character is 2 and so on. The returned substring contains
6625 * those characters for which the position of the character is greater than
6626 * or equal to the second argument and, if the third argument is specified,
6627 * less than the sum of the second and third arguments; the comparisons
6628 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6629 * - substring("12345", 1.5, 2.6) returns "234"
6630 * - substring("12345", 0, 3) returns "12"
6631 * - substring("12345", 0 div 0, 3) returns ""
6632 * - substring("12345", 1, 0 div 0) returns ""
6633 * - substring("12345", -42, 1 div 0) returns "12345"
6634 * - substring("12345", -1 div 0, 1 div 0) returns ""
6635 */
6636void
6637xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6638 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006639 double le=0, in;
6640 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006641 xmlChar *ret;
6642
Owen Taylor3473f882001-02-23 17:55:21 +00006643 if (nargs < 2) {
6644 CHECK_ARITY(2);
6645 }
6646 if (nargs > 3) {
6647 CHECK_ARITY(3);
6648 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006649 /*
6650 * take care of possible last (position) argument
6651 */
Owen Taylor3473f882001-02-23 17:55:21 +00006652 if (nargs == 3) {
6653 CAST_TO_NUMBER;
6654 CHECK_TYPE(XPATH_NUMBER);
6655 len = valuePop(ctxt);
6656 le = len->floatval;
6657 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006658 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006659
Owen Taylor3473f882001-02-23 17:55:21 +00006660 CAST_TO_NUMBER;
6661 CHECK_TYPE(XPATH_NUMBER);
6662 start = valuePop(ctxt);
6663 in = start->floatval;
6664 xmlXPathFreeObject(start);
6665 CAST_TO_STRING;
6666 CHECK_TYPE(XPATH_STRING);
6667 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006668 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006669
Daniel Veillard97ac1312001-05-30 19:14:17 +00006670 /*
6671 * If last pos not present, calculate last position
6672 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006673 if (nargs != 3) {
6674 le = (double)m;
6675 if (in < 1.0)
6676 in = 1.0;
6677 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006678
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006679 /* Need to check for the special cases where either
6680 * the index is NaN, the length is NaN, or both
6681 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006682 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006683 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006684 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006685 * To meet the requirements of the spec, the arguments
6686 * must be converted to integer format before
6687 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006688 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006689 * First we go to integer form, rounding up
6690 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006691 */
6692 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006693 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006694
Daniel Veillard9e412302002-06-10 15:59:44 +00006695 if (xmlXPathIsInf(le) == 1) {
6696 l = m;
6697 if (i < 1)
6698 i = 1;
6699 }
6700 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6701 l = 0;
6702 else {
6703 l = (int) le;
6704 if (((double)l)+0.5 <= le) l++;
6705 }
6706
6707 /* Now we normalize inidices */
6708 i -= 1;
6709 l += i;
6710 if (i < 0)
6711 i = 0;
6712 if (l > m)
6713 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006714
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006715 /* number of chars to copy */
6716 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006717
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006718 ret = xmlUTF8Strsub(str->stringval, i, l);
6719 }
6720 else {
6721 ret = NULL;
6722 }
6723
Owen Taylor3473f882001-02-23 17:55:21 +00006724 if (ret == NULL)
6725 valuePush(ctxt, xmlXPathNewCString(""));
6726 else {
6727 valuePush(ctxt, xmlXPathNewString(ret));
6728 xmlFree(ret);
6729 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006730
Owen Taylor3473f882001-02-23 17:55:21 +00006731 xmlXPathFreeObject(str);
6732}
6733
6734/**
6735 * xmlXPathSubstringBeforeFunction:
6736 * @ctxt: the XPath Parser context
6737 * @nargs: the number of arguments
6738 *
6739 * Implement the substring-before() XPath function
6740 * string substring-before(string, string)
6741 * The substring-before function returns the substring of the first
6742 * argument string that precedes the first occurrence of the second
6743 * argument string in the first argument string, or the empty string
6744 * if the first argument string does not contain the second argument
6745 * string. For example, substring-before("1999/04/01","/") returns 1999.
6746 */
6747void
6748xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6749 xmlXPathObjectPtr str;
6750 xmlXPathObjectPtr find;
6751 xmlBufferPtr target;
6752 const xmlChar *point;
6753 int offset;
6754
6755 CHECK_ARITY(2);
6756 CAST_TO_STRING;
6757 find = valuePop(ctxt);
6758 CAST_TO_STRING;
6759 str = valuePop(ctxt);
6760
6761 target = xmlBufferCreate();
6762 if (target) {
6763 point = xmlStrstr(str->stringval, find->stringval);
6764 if (point) {
6765 offset = (int)(point - str->stringval);
6766 xmlBufferAdd(target, str->stringval, offset);
6767 }
6768 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6769 xmlBufferFree(target);
6770 }
6771
6772 xmlXPathFreeObject(str);
6773 xmlXPathFreeObject(find);
6774}
6775
6776/**
6777 * xmlXPathSubstringAfterFunction:
6778 * @ctxt: the XPath Parser context
6779 * @nargs: the number of arguments
6780 *
6781 * Implement the substring-after() XPath function
6782 * string substring-after(string, string)
6783 * The substring-after function returns the substring of the first
6784 * argument string that follows the first occurrence of the second
6785 * argument string in the first argument string, or the empty stringi
6786 * if the first argument string does not contain the second argument
6787 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6788 * and substring-after("1999/04/01","19") returns 99/04/01.
6789 */
6790void
6791xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6792 xmlXPathObjectPtr str;
6793 xmlXPathObjectPtr find;
6794 xmlBufferPtr target;
6795 const xmlChar *point;
6796 int offset;
6797
6798 CHECK_ARITY(2);
6799 CAST_TO_STRING;
6800 find = valuePop(ctxt);
6801 CAST_TO_STRING;
6802 str = valuePop(ctxt);
6803
6804 target = xmlBufferCreate();
6805 if (target) {
6806 point = xmlStrstr(str->stringval, find->stringval);
6807 if (point) {
6808 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6809 xmlBufferAdd(target, &str->stringval[offset],
6810 xmlStrlen(str->stringval) - offset);
6811 }
6812 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6813 xmlBufferFree(target);
6814 }
6815
6816 xmlXPathFreeObject(str);
6817 xmlXPathFreeObject(find);
6818}
6819
6820/**
6821 * xmlXPathNormalizeFunction:
6822 * @ctxt: the XPath Parser context
6823 * @nargs: the number of arguments
6824 *
6825 * Implement the normalize-space() XPath function
6826 * string normalize-space(string?)
6827 * The normalize-space function returns the argument string with white
6828 * space normalized by stripping leading and trailing whitespace
6829 * and replacing sequences of whitespace characters by a single
6830 * space. Whitespace characters are the same allowed by the S production
6831 * in XML. If the argument is omitted, it defaults to the context
6832 * node converted to a string, in other words the value of the context node.
6833 */
6834void
6835xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6836 xmlXPathObjectPtr obj = NULL;
6837 xmlChar *source = NULL;
6838 xmlBufferPtr target;
6839 xmlChar blank;
6840
Daniel Veillarda82b1822004-11-08 16:24:57 +00006841 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006842 if (nargs == 0) {
6843 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006844 valuePush(ctxt,
6845 xmlXPathWrapString(
6846 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006847 nargs = 1;
6848 }
6849
6850 CHECK_ARITY(1);
6851 CAST_TO_STRING;
6852 CHECK_TYPE(XPATH_STRING);
6853 obj = valuePop(ctxt);
6854 source = obj->stringval;
6855
6856 target = xmlBufferCreate();
6857 if (target && source) {
6858
6859 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006860 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006861 source++;
6862
6863 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6864 blank = 0;
6865 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006866 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006867 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006868 } else {
6869 if (blank) {
6870 xmlBufferAdd(target, &blank, 1);
6871 blank = 0;
6872 }
6873 xmlBufferAdd(target, source, 1);
6874 }
6875 source++;
6876 }
6877
6878 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6879 xmlBufferFree(target);
6880 }
6881 xmlXPathFreeObject(obj);
6882}
6883
6884/**
6885 * xmlXPathTranslateFunction:
6886 * @ctxt: the XPath Parser context
6887 * @nargs: the number of arguments
6888 *
6889 * Implement the translate() XPath function
6890 * string translate(string, string, string)
6891 * The translate function returns the first argument string with
6892 * occurrences of characters in the second argument string replaced
6893 * by the character at the corresponding position in the third argument
6894 * string. For example, translate("bar","abc","ABC") returns the string
6895 * BAr. If there is a character in the second argument string with no
6896 * character at a corresponding position in the third argument string
6897 * (because the second argument string is longer than the third argument
6898 * string), then occurrences of that character in the first argument
6899 * string are removed. For example, translate("--aaa--","abc-","ABC")
6900 * returns "AAA". If a character occurs more than once in second
6901 * argument string, then the first occurrence determines the replacement
6902 * character. If the third argument string is longer than the second
6903 * argument string, then excess characters are ignored.
6904 */
6905void
6906xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006907 xmlXPathObjectPtr str;
6908 xmlXPathObjectPtr from;
6909 xmlXPathObjectPtr to;
6910 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006911 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006912 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00006913 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006914 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006915
Daniel Veillarde043ee12001-04-16 14:08:07 +00006916 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006917
Daniel Veillarde043ee12001-04-16 14:08:07 +00006918 CAST_TO_STRING;
6919 to = valuePop(ctxt);
6920 CAST_TO_STRING;
6921 from = valuePop(ctxt);
6922 CAST_TO_STRING;
6923 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006924
Daniel Veillarde043ee12001-04-16 14:08:07 +00006925 target = xmlBufferCreate();
6926 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006927 max = xmlUTF8Strlen(to->stringval);
6928 for (cptr = str->stringval; (ch=*cptr); ) {
6929 offset = xmlUTF8Strloc(from->stringval, cptr);
6930 if (offset >= 0) {
6931 if (offset < max) {
6932 point = xmlUTF8Strpos(to->stringval, offset);
6933 if (point)
6934 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6935 }
6936 } else
6937 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6938
6939 /* Step to next character in input */
6940 cptr++;
6941 if ( ch & 0x80 ) {
6942 /* if not simple ascii, verify proper format */
6943 if ( (ch & 0xc0) != 0xc0 ) {
6944 xmlGenericError(xmlGenericErrorContext,
6945 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6946 break;
6947 }
6948 /* then skip over remaining bytes for this char */
6949 while ( (ch <<= 1) & 0x80 )
6950 if ( (*cptr++ & 0xc0) != 0x80 ) {
6951 xmlGenericError(xmlGenericErrorContext,
6952 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6953 break;
6954 }
6955 if (ch & 0x80) /* must have had error encountered */
6956 break;
6957 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006958 }
Owen Taylor3473f882001-02-23 17:55:21 +00006959 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006960 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6961 xmlBufferFree(target);
6962 xmlXPathFreeObject(str);
6963 xmlXPathFreeObject(from);
6964 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006965}
6966
6967/**
6968 * xmlXPathBooleanFunction:
6969 * @ctxt: the XPath Parser context
6970 * @nargs: the number of arguments
6971 *
6972 * Implement the boolean() XPath function
6973 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00006974 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006975 * - a number is true if and only if it is neither positive or
6976 * negative zero nor NaN
6977 * - a node-set is true if and only if it is non-empty
6978 * - a string is true if and only if its length is non-zero
6979 */
6980void
6981xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6982 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006983
6984 CHECK_ARITY(1);
6985 cur = valuePop(ctxt);
6986 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006987 cur = xmlXPathConvertBoolean(cur);
6988 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006989}
6990
6991/**
6992 * xmlXPathNotFunction:
6993 * @ctxt: the XPath Parser context
6994 * @nargs: the number of arguments
6995 *
6996 * Implement the not() XPath function
6997 * boolean not(boolean)
6998 * The not function returns true if its argument is false,
6999 * and false otherwise.
7000 */
7001void
7002xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7003 CHECK_ARITY(1);
7004 CAST_TO_BOOLEAN;
7005 CHECK_TYPE(XPATH_BOOLEAN);
7006 ctxt->value->boolval = ! ctxt->value->boolval;
7007}
7008
7009/**
7010 * xmlXPathTrueFunction:
7011 * @ctxt: the XPath Parser context
7012 * @nargs: the number of arguments
7013 *
7014 * Implement the true() XPath function
7015 * boolean true()
7016 */
7017void
7018xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7019 CHECK_ARITY(0);
7020 valuePush(ctxt, xmlXPathNewBoolean(1));
7021}
7022
7023/**
7024 * xmlXPathFalseFunction:
7025 * @ctxt: the XPath Parser context
7026 * @nargs: the number of arguments
7027 *
7028 * Implement the false() XPath function
7029 * boolean false()
7030 */
7031void
7032xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7033 CHECK_ARITY(0);
7034 valuePush(ctxt, xmlXPathNewBoolean(0));
7035}
7036
7037/**
7038 * xmlXPathLangFunction:
7039 * @ctxt: the XPath Parser context
7040 * @nargs: the number of arguments
7041 *
7042 * Implement the lang() XPath function
7043 * boolean lang(string)
7044 * The lang function returns true or false depending on whether the
7045 * language of the context node as specified by xml:lang attributes
7046 * is the same as or is a sublanguage of the language specified by
7047 * the argument string. The language of the context node is determined
7048 * by the value of the xml:lang attribute on the context node, or, if
7049 * the context node has no xml:lang attribute, by the value of the
7050 * xml:lang attribute on the nearest ancestor of the context node that
7051 * has an xml:lang attribute. If there is no such attribute, then lang
7052 * returns false. If there is such an attribute, then lang returns
7053 * true if the attribute value is equal to the argument ignoring case,
7054 * or if there is some suffix starting with - such that the attribute
7055 * value is equal to the argument ignoring that suffix of the attribute
7056 * value and ignoring case.
7057 */
7058void
7059xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7060 xmlXPathObjectPtr val;
7061 const xmlChar *theLang;
7062 const xmlChar *lang;
7063 int ret = 0;
7064 int i;
7065
7066 CHECK_ARITY(1);
7067 CAST_TO_STRING;
7068 CHECK_TYPE(XPATH_STRING);
7069 val = valuePop(ctxt);
7070 lang = val->stringval;
7071 theLang = xmlNodeGetLang(ctxt->context->node);
7072 if ((theLang != NULL) && (lang != NULL)) {
7073 for (i = 0;lang[i] != 0;i++)
7074 if (toupper(lang[i]) != toupper(theLang[i]))
7075 goto not_equal;
7076 ret = 1;
7077 }
7078not_equal:
William M. Bracka59ddb52004-02-25 08:12:32 +00007079 xmlFree((void *)theLang);
Owen Taylor3473f882001-02-23 17:55:21 +00007080 xmlXPathFreeObject(val);
7081 valuePush(ctxt, xmlXPathNewBoolean(ret));
7082}
7083
7084/**
7085 * xmlXPathNumberFunction:
7086 * @ctxt: the XPath Parser context
7087 * @nargs: the number of arguments
7088 *
7089 * Implement the number() XPath function
7090 * number number(object?)
7091 */
7092void
7093xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7094 xmlXPathObjectPtr cur;
7095 double res;
7096
Daniel Veillarda82b1822004-11-08 16:24:57 +00007097 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007098 if (nargs == 0) {
7099 if (ctxt->context->node == NULL) {
7100 valuePush(ctxt, xmlXPathNewFloat(0.0));
7101 } else {
7102 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7103
7104 res = xmlXPathStringEvalNumber(content);
7105 valuePush(ctxt, xmlXPathNewFloat(res));
7106 xmlFree(content);
7107 }
7108 return;
7109 }
7110
7111 CHECK_ARITY(1);
7112 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007113 cur = xmlXPathConvertNumber(cur);
7114 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007115}
7116
7117/**
7118 * xmlXPathSumFunction:
7119 * @ctxt: the XPath Parser context
7120 * @nargs: the number of arguments
7121 *
7122 * Implement the sum() XPath function
7123 * number sum(node-set)
7124 * The sum function returns the sum of the values of the nodes in
7125 * the argument node-set.
7126 */
7127void
7128xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7129 xmlXPathObjectPtr cur;
7130 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007131 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007132
7133 CHECK_ARITY(1);
7134 if ((ctxt->value == NULL) ||
7135 ((ctxt->value->type != XPATH_NODESET) &&
7136 (ctxt->value->type != XPATH_XSLT_TREE)))
7137 XP_ERROR(XPATH_INVALID_TYPE);
7138 cur = valuePop(ctxt);
7139
William M. Brack08171912003-12-29 02:52:11 +00007140 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007141 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7142 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007143 }
7144 }
William M. Brack08171912003-12-29 02:52:11 +00007145 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007146 xmlXPathFreeObject(cur);
7147}
7148
7149/**
7150 * xmlXPathFloorFunction:
7151 * @ctxt: the XPath Parser context
7152 * @nargs: the number of arguments
7153 *
7154 * Implement the floor() XPath function
7155 * number floor(number)
7156 * The floor function returns the largest (closest to positive infinity)
7157 * number that is not greater than the argument and that is an integer.
7158 */
7159void
7160xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007161 double f;
7162
Owen Taylor3473f882001-02-23 17:55:21 +00007163 CHECK_ARITY(1);
7164 CAST_TO_NUMBER;
7165 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007166
7167 f = (double)((int) ctxt->value->floatval);
7168 if (f != ctxt->value->floatval) {
7169 if (ctxt->value->floatval > 0)
7170 ctxt->value->floatval = f;
7171 else
7172 ctxt->value->floatval = f - 1;
7173 }
Owen Taylor3473f882001-02-23 17:55:21 +00007174}
7175
7176/**
7177 * xmlXPathCeilingFunction:
7178 * @ctxt: the XPath Parser context
7179 * @nargs: the number of arguments
7180 *
7181 * Implement the ceiling() XPath function
7182 * number ceiling(number)
7183 * The ceiling function returns the smallest (closest to negative infinity)
7184 * number that is not less than the argument and that is an integer.
7185 */
7186void
7187xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7188 double f;
7189
7190 CHECK_ARITY(1);
7191 CAST_TO_NUMBER;
7192 CHECK_TYPE(XPATH_NUMBER);
7193
7194#if 0
7195 ctxt->value->floatval = ceil(ctxt->value->floatval);
7196#else
7197 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007198 if (f != ctxt->value->floatval) {
7199 if (ctxt->value->floatval > 0)
7200 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007201 else {
7202 if (ctxt->value->floatval < 0 && f == 0)
7203 ctxt->value->floatval = xmlXPathNZERO;
7204 else
7205 ctxt->value->floatval = f;
7206 }
7207
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007208 }
Owen Taylor3473f882001-02-23 17:55:21 +00007209#endif
7210}
7211
7212/**
7213 * xmlXPathRoundFunction:
7214 * @ctxt: the XPath Parser context
7215 * @nargs: the number of arguments
7216 *
7217 * Implement the round() XPath function
7218 * number round(number)
7219 * The round function returns the number that is closest to the
7220 * argument and that is an integer. If there are two such numbers,
7221 * then the one that is even is returned.
7222 */
7223void
7224xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7225 double f;
7226
7227 CHECK_ARITY(1);
7228 CAST_TO_NUMBER;
7229 CHECK_TYPE(XPATH_NUMBER);
7230
Daniel Veillardcda96922001-08-21 10:56:31 +00007231 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7232 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7233 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007234 (ctxt->value->floatval == 0.0))
7235 return;
7236
Owen Taylor3473f882001-02-23 17:55:21 +00007237 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007238 if (ctxt->value->floatval < 0) {
7239 if (ctxt->value->floatval < f - 0.5)
7240 ctxt->value->floatval = f - 1;
7241 else
7242 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007243 if (ctxt->value->floatval == 0)
7244 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007245 } else {
7246 if (ctxt->value->floatval < f + 0.5)
7247 ctxt->value->floatval = f;
7248 else
7249 ctxt->value->floatval = f + 1;
7250 }
Owen Taylor3473f882001-02-23 17:55:21 +00007251}
7252
7253/************************************************************************
7254 * *
7255 * The Parser *
7256 * *
7257 ************************************************************************/
7258
7259/*
William M. Brack08171912003-12-29 02:52:11 +00007260 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007261 * implementation.
7262 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007263static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007264static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007265static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007266static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007267static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7268 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007269
7270/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007271 * xmlXPathCurrentChar:
7272 * @ctxt: the XPath parser context
7273 * @cur: pointer to the beginning of the char
7274 * @len: pointer to the length of the char read
7275 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007276 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007277 * bytes in the input buffer.
7278 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007279 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007280 */
7281
7282static int
7283xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7284 unsigned char c;
7285 unsigned int val;
7286 const xmlChar *cur;
7287
7288 if (ctxt == NULL)
7289 return(0);
7290 cur = ctxt->cur;
7291
7292 /*
7293 * We are supposed to handle UTF8, check it's valid
7294 * From rfc2044: encoding of the Unicode values on UTF-8:
7295 *
7296 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7297 * 0000 0000-0000 007F 0xxxxxxx
7298 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7299 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7300 *
7301 * Check for the 0x110000 limit too
7302 */
7303 c = *cur;
7304 if (c & 0x80) {
7305 if ((cur[1] & 0xc0) != 0x80)
7306 goto encoding_error;
7307 if ((c & 0xe0) == 0xe0) {
7308
7309 if ((cur[2] & 0xc0) != 0x80)
7310 goto encoding_error;
7311 if ((c & 0xf0) == 0xf0) {
7312 if (((c & 0xf8) != 0xf0) ||
7313 ((cur[3] & 0xc0) != 0x80))
7314 goto encoding_error;
7315 /* 4-byte code */
7316 *len = 4;
7317 val = (cur[0] & 0x7) << 18;
7318 val |= (cur[1] & 0x3f) << 12;
7319 val |= (cur[2] & 0x3f) << 6;
7320 val |= cur[3] & 0x3f;
7321 } else {
7322 /* 3-byte code */
7323 *len = 3;
7324 val = (cur[0] & 0xf) << 12;
7325 val |= (cur[1] & 0x3f) << 6;
7326 val |= cur[2] & 0x3f;
7327 }
7328 } else {
7329 /* 2-byte code */
7330 *len = 2;
7331 val = (cur[0] & 0x1f) << 6;
7332 val |= cur[1] & 0x3f;
7333 }
7334 if (!IS_CHAR(val)) {
7335 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7336 }
7337 return(val);
7338 } else {
7339 /* 1-byte code */
7340 *len = 1;
7341 return((int) *cur);
7342 }
7343encoding_error:
7344 /*
William M. Brack08171912003-12-29 02:52:11 +00007345 * If we detect an UTF8 error that probably means that the
7346 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007347 * declaration header. Report the error and switch the encoding
7348 * to ISO-Latin-1 (if you don't like this policy, just declare the
7349 * encoding !)
7350 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007351 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007352 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007353}
7354
7355/**
Owen Taylor3473f882001-02-23 17:55:21 +00007356 * xmlXPathParseNCName:
7357 * @ctxt: the XPath Parser context
7358 *
7359 * parse an XML namespace non qualified name.
7360 *
7361 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7362 *
7363 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7364 * CombiningChar | Extender
7365 *
7366 * Returns the namespace name or NULL
7367 */
7368
7369xmlChar *
7370xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007371 const xmlChar *in;
7372 xmlChar *ret;
7373 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007374
Daniel Veillarda82b1822004-11-08 16:24:57 +00007375 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00007376 /*
7377 * Accelerator for simple ASCII names
7378 */
7379 in = ctxt->cur;
7380 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7381 ((*in >= 0x41) && (*in <= 0x5A)) ||
7382 (*in == '_')) {
7383 in++;
7384 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7385 ((*in >= 0x41) && (*in <= 0x5A)) ||
7386 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007387 (*in == '_') || (*in == '.') ||
7388 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007389 in++;
7390 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7391 (*in == '[') || (*in == ']') || (*in == ':') ||
7392 (*in == '@') || (*in == '*')) {
7393 count = in - ctxt->cur;
7394 if (count == 0)
7395 return(NULL);
7396 ret = xmlStrndup(ctxt->cur, count);
7397 ctxt->cur = in;
7398 return(ret);
7399 }
7400 }
7401 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007402}
7403
Daniel Veillard2156a562001-04-28 12:24:34 +00007404
Owen Taylor3473f882001-02-23 17:55:21 +00007405/**
7406 * xmlXPathParseQName:
7407 * @ctxt: the XPath Parser context
7408 * @prefix: a xmlChar **
7409 *
7410 * parse an XML qualified name
7411 *
7412 * [NS 5] QName ::= (Prefix ':')? LocalPart
7413 *
7414 * [NS 6] Prefix ::= NCName
7415 *
7416 * [NS 7] LocalPart ::= NCName
7417 *
7418 * Returns the function returns the local part, and prefix is updated
7419 * to get the Prefix if any.
7420 */
7421
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007422static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007423xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7424 xmlChar *ret = NULL;
7425
7426 *prefix = NULL;
7427 ret = xmlXPathParseNCName(ctxt);
7428 if (CUR == ':') {
7429 *prefix = ret;
7430 NEXT;
7431 ret = xmlXPathParseNCName(ctxt);
7432 }
7433 return(ret);
7434}
7435
7436/**
7437 * xmlXPathParseName:
7438 * @ctxt: the XPath Parser context
7439 *
7440 * parse an XML name
7441 *
7442 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7443 * CombiningChar | Extender
7444 *
7445 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7446 *
7447 * Returns the namespace name or NULL
7448 */
7449
7450xmlChar *
7451xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007452 const xmlChar *in;
7453 xmlChar *ret;
7454 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007455
Daniel Veillarda82b1822004-11-08 16:24:57 +00007456 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007457 /*
7458 * Accelerator for simple ASCII names
7459 */
7460 in = ctxt->cur;
7461 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7462 ((*in >= 0x41) && (*in <= 0x5A)) ||
7463 (*in == '_') || (*in == ':')) {
7464 in++;
7465 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7466 ((*in >= 0x41) && (*in <= 0x5A)) ||
7467 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007468 (*in == '_') || (*in == '-') ||
7469 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007470 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007471 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007472 count = in - ctxt->cur;
7473 ret = xmlStrndup(ctxt->cur, count);
7474 ctxt->cur = in;
7475 return(ret);
7476 }
7477 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007478 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007479}
7480
Daniel Veillard61d80a22001-04-27 17:13:01 +00007481static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007482xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007483 xmlChar buf[XML_MAX_NAMELEN + 5];
7484 int len = 0, l;
7485 int c;
7486
7487 /*
7488 * Handler for more complex cases
7489 */
7490 c = CUR_CHAR(l);
7491 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007492 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7493 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007494 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007495 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007496 return(NULL);
7497 }
7498
7499 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7500 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7501 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007502 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007503 (IS_COMBINING(c)) ||
7504 (IS_EXTENDER(c)))) {
7505 COPY_BUF(l,buf,len,c);
7506 NEXTL(l);
7507 c = CUR_CHAR(l);
7508 if (len >= XML_MAX_NAMELEN) {
7509 /*
7510 * Okay someone managed to make a huge name, so he's ready to pay
7511 * for the processing speed.
7512 */
7513 xmlChar *buffer;
7514 int max = len * 2;
7515
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007516 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007517 if (buffer == NULL) {
7518 XP_ERROR0(XPATH_MEMORY_ERROR);
7519 }
7520 memcpy(buffer, buf, len);
7521 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7522 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007523 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007524 (IS_COMBINING(c)) ||
7525 (IS_EXTENDER(c))) {
7526 if (len + 10 > max) {
7527 max *= 2;
7528 buffer = (xmlChar *) xmlRealloc(buffer,
7529 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007530 if (buffer == NULL) {
7531 XP_ERROR0(XPATH_MEMORY_ERROR);
7532 }
7533 }
7534 COPY_BUF(l,buffer,len,c);
7535 NEXTL(l);
7536 c = CUR_CHAR(l);
7537 }
7538 buffer[len] = 0;
7539 return(buffer);
7540 }
7541 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007542 if (len == 0)
7543 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007544 return(xmlStrndup(buf, len));
7545}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007546
7547#define MAX_FRAC 20
7548
William M. Brack372a4452004-02-17 13:09:23 +00007549/*
7550 * These are used as divisors for the fractional part of a number.
7551 * Since the table includes 1.0 (representing '0' fractional digits),
7552 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
7553 */
7554static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007555 1.0, 10.0, 100.0, 1000.0, 10000.0,
7556 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7557 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7558 100000000000000.0,
7559 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00007560 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00007561};
7562
Owen Taylor3473f882001-02-23 17:55:21 +00007563/**
7564 * xmlXPathStringEvalNumber:
7565 * @str: A string to scan
7566 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007567 * [30a] Float ::= Number ('e' Digits?)?
7568 *
Owen Taylor3473f882001-02-23 17:55:21 +00007569 * [30] Number ::= Digits ('.' Digits?)?
7570 * | '.' Digits
7571 * [31] Digits ::= [0-9]+
7572 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007573 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007574 * In complement of the Number expression, this function also handles
7575 * negative values : '-' Number.
7576 *
7577 * Returns the double value.
7578 */
7579double
7580xmlXPathStringEvalNumber(const xmlChar *str) {
7581 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007582 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007583 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007584 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007585 int exponent = 0;
7586 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007587#ifdef __GNUC__
7588 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007589 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007590#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007591 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007592 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007593 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7594 return(xmlXPathNAN);
7595 }
7596 if (*cur == '-') {
7597 isneg = 1;
7598 cur++;
7599 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007600
7601#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007602 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007603 * tmp/temp is a workaround against a gcc compiler bug
7604 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007605 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007606 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007607 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007608 ret = ret * 10;
7609 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007610 ok = 1;
7611 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007612 temp = (double) tmp;
7613 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007614 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007615#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007616 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007617 while ((*cur >= '0') && (*cur <= '9')) {
7618 ret = ret * 10 + (*cur - '0');
7619 ok = 1;
7620 cur++;
7621 }
7622#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007623
Owen Taylor3473f882001-02-23 17:55:21 +00007624 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007625 int v, frac = 0;
7626 double fraction = 0;
7627
Owen Taylor3473f882001-02-23 17:55:21 +00007628 cur++;
7629 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7630 return(xmlXPathNAN);
7631 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007632 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7633 v = (*cur - '0');
7634 fraction = fraction * 10 + v;
7635 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007636 cur++;
7637 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007638 fraction /= my_pow10[frac];
7639 ret = ret + fraction;
7640 while ((*cur >= '0') && (*cur <= '9'))
7641 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007642 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007643 if ((*cur == 'e') || (*cur == 'E')) {
7644 cur++;
7645 if (*cur == '-') {
7646 is_exponent_negative = 1;
7647 cur++;
William M. Brack99127052004-05-24 02:52:28 +00007648 } else if (*cur == '+') {
7649 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007650 }
7651 while ((*cur >= '0') && (*cur <= '9')) {
7652 exponent = exponent * 10 + (*cur - '0');
7653 cur++;
7654 }
7655 }
William M. Brack76e95df2003-10-18 16:20:14 +00007656 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007657 if (*cur != 0) return(xmlXPathNAN);
7658 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007659 if (is_exponent_negative) exponent = -exponent;
7660 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007661 return(ret);
7662}
7663
7664/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007665 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007666 * @ctxt: the XPath Parser context
7667 *
7668 * [30] Number ::= Digits ('.' Digits?)?
7669 * | '.' Digits
7670 * [31] Digits ::= [0-9]+
7671 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007672 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007673 *
7674 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007675static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007676xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7677{
Owen Taylor3473f882001-02-23 17:55:21 +00007678 double ret = 0.0;
7679 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007680 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007681 int exponent = 0;
7682 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007683#ifdef __GNUC__
7684 unsigned long tmp = 0;
7685 double temp;
7686#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007687
7688 CHECK_ERROR;
7689 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7690 XP_ERROR(XPATH_NUMBER_ERROR);
7691 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007692#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007693 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007694 * tmp/temp is a workaround against a gcc compiler bug
7695 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007696 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007697 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007698 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007699 ret = ret * 10;
7700 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007701 ok = 1;
7702 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007703 temp = (double) tmp;
7704 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007705 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007706#else
7707 ret = 0;
7708 while ((CUR >= '0') && (CUR <= '9')) {
7709 ret = ret * 10 + (CUR - '0');
7710 ok = 1;
7711 NEXT;
7712 }
7713#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007714 if (CUR == '.') {
7715 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007716 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7717 XP_ERROR(XPATH_NUMBER_ERROR);
7718 }
7719 while ((CUR >= '0') && (CUR <= '9')) {
7720 mult /= 10;
7721 ret = ret + (CUR - '0') * mult;
7722 NEXT;
7723 }
Owen Taylor3473f882001-02-23 17:55:21 +00007724 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007725 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007726 NEXT;
7727 if (CUR == '-') {
7728 is_exponent_negative = 1;
7729 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00007730 } else if (CUR == '+') {
7731 NEXT;
7732 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007733 while ((CUR >= '0') && (CUR <= '9')) {
7734 exponent = exponent * 10 + (CUR - '0');
7735 NEXT;
7736 }
7737 if (is_exponent_negative)
7738 exponent = -exponent;
7739 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007740 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007741 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007742 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007743}
7744
7745/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007746 * xmlXPathParseLiteral:
7747 * @ctxt: the XPath Parser context
7748 *
7749 * Parse a Literal
7750 *
7751 * [29] Literal ::= '"' [^"]* '"'
7752 * | "'" [^']* "'"
7753 *
7754 * Returns the value found or NULL in case of error
7755 */
7756static xmlChar *
7757xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7758 const xmlChar *q;
7759 xmlChar *ret = NULL;
7760
7761 if (CUR == '"') {
7762 NEXT;
7763 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007764 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007765 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007766 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007767 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7768 } else {
7769 ret = xmlStrndup(q, CUR_PTR - q);
7770 NEXT;
7771 }
7772 } else if (CUR == '\'') {
7773 NEXT;
7774 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007775 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007776 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007777 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007778 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7779 } else {
7780 ret = xmlStrndup(q, CUR_PTR - q);
7781 NEXT;
7782 }
7783 } else {
7784 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7785 }
7786 return(ret);
7787}
7788
7789/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007790 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007791 * @ctxt: the XPath Parser context
7792 *
7793 * Parse a Literal and push it on the stack.
7794 *
7795 * [29] Literal ::= '"' [^"]* '"'
7796 * | "'" [^']* "'"
7797 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007798 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007799 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007800static void
7801xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007802 const xmlChar *q;
7803 xmlChar *ret = NULL;
7804
7805 if (CUR == '"') {
7806 NEXT;
7807 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007808 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007809 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007810 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007811 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7812 } else {
7813 ret = xmlStrndup(q, CUR_PTR - q);
7814 NEXT;
7815 }
7816 } else if (CUR == '\'') {
7817 NEXT;
7818 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007819 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007820 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007821 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007822 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7823 } else {
7824 ret = xmlStrndup(q, CUR_PTR - q);
7825 NEXT;
7826 }
7827 } else {
7828 XP_ERROR(XPATH_START_LITERAL_ERROR);
7829 }
7830 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007831 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7832 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007833 xmlFree(ret);
7834}
7835
7836/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007837 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007838 * @ctxt: the XPath Parser context
7839 *
7840 * Parse a VariableReference, evaluate it and push it on the stack.
7841 *
7842 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00007843 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00007844 * of any of the types that are possible for the value of an expression,
7845 * and may also be of additional types not specified here.
7846 *
7847 * Early evaluation is possible since:
7848 * The variable bindings [...] used to evaluate a subexpression are
7849 * always the same as those used to evaluate the containing expression.
7850 *
7851 * [36] VariableReference ::= '$' QName
7852 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007853static void
7854xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007855 xmlChar *name;
7856 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007857
7858 SKIP_BLANKS;
7859 if (CUR != '$') {
7860 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7861 }
7862 NEXT;
7863 name = xmlXPathParseQName(ctxt, &prefix);
7864 if (name == NULL) {
7865 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7866 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007867 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007868 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7869 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007870 SKIP_BLANKS;
7871}
7872
7873/**
7874 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007875 * @name: a name string
7876 *
7877 * Is the name given a NodeType one.
7878 *
7879 * [38] NodeType ::= 'comment'
7880 * | 'text'
7881 * | 'processing-instruction'
7882 * | 'node'
7883 *
7884 * Returns 1 if true 0 otherwise
7885 */
7886int
7887xmlXPathIsNodeType(const xmlChar *name) {
7888 if (name == NULL)
7889 return(0);
7890
Daniel Veillard1971ee22002-01-31 20:29:19 +00007891 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007892 return(1);
7893 if (xmlStrEqual(name, BAD_CAST "text"))
7894 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007895 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007896 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007897 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007898 return(1);
7899 return(0);
7900}
7901
7902/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007903 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007904 * @ctxt: the XPath Parser context
7905 *
7906 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7907 * [17] Argument ::= Expr
7908 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007909 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007910 * pushed on the stack
7911 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007912static void
7913xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007914 xmlChar *name;
7915 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007916 int nbargs = 0;
7917
7918 name = xmlXPathParseQName(ctxt, &prefix);
7919 if (name == NULL) {
7920 XP_ERROR(XPATH_EXPR_ERROR);
7921 }
7922 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007923#ifdef DEBUG_EXPR
7924 if (prefix == NULL)
7925 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7926 name);
7927 else
7928 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7929 prefix, name);
7930#endif
7931
Owen Taylor3473f882001-02-23 17:55:21 +00007932 if (CUR != '(') {
7933 XP_ERROR(XPATH_EXPR_ERROR);
7934 }
7935 NEXT;
7936 SKIP_BLANKS;
7937
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007938 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007939 if (CUR != ')') {
7940 while (CUR != 0) {
7941 int op1 = ctxt->comp->last;
7942 ctxt->comp->last = -1;
7943 xmlXPathCompileExpr(ctxt);
7944 CHECK_ERROR;
7945 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7946 nbargs++;
7947 if (CUR == ')') break;
7948 if (CUR != ',') {
7949 XP_ERROR(XPATH_EXPR_ERROR);
7950 }
7951 NEXT;
7952 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007953 }
Owen Taylor3473f882001-02-23 17:55:21 +00007954 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007955 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7956 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007957 NEXT;
7958 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007959}
7960
7961/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007962 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007963 * @ctxt: the XPath Parser context
7964 *
7965 * [15] PrimaryExpr ::= VariableReference
7966 * | '(' Expr ')'
7967 * | Literal
7968 * | Number
7969 * | FunctionCall
7970 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007971 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007972 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007973static void
7974xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007975 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007976 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007977 else if (CUR == '(') {
7978 NEXT;
7979 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007980 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007981 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007982 if (CUR != ')') {
7983 XP_ERROR(XPATH_EXPR_ERROR);
7984 }
7985 NEXT;
7986 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00007987 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007988 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007989 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007990 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007991 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007992 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007993 }
7994 SKIP_BLANKS;
7995}
7996
7997/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007998 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007999 * @ctxt: the XPath Parser context
8000 *
8001 * [20] FilterExpr ::= PrimaryExpr
8002 * | FilterExpr Predicate
8003 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008004 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008005 * Square brackets are used to filter expressions in the same way that
8006 * they are used in location paths. It is an error if the expression to
8007 * be filtered does not evaluate to a node-set. The context node list
8008 * used for evaluating the expression in square brackets is the node-set
8009 * to be filtered listed in document order.
8010 */
8011
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008012static void
8013xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8014 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008015 CHECK_ERROR;
8016 SKIP_BLANKS;
8017
8018 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008019 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00008020 SKIP_BLANKS;
8021 }
8022
8023
8024}
8025
8026/**
8027 * xmlXPathScanName:
8028 * @ctxt: the XPath Parser context
8029 *
8030 * Trickery: parse an XML name but without consuming the input flow
8031 * Needed to avoid insanity in the parser state.
8032 *
8033 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8034 * CombiningChar | Extender
8035 *
8036 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8037 *
8038 * [6] Names ::= Name (S Name)*
8039 *
8040 * Returns the Name parsed or NULL
8041 */
8042
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008043static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00008044xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +00008045 int len = 0, l;
8046 int c;
Daniel Veillard03226812004-11-01 14:55:21 +00008047 const xmlChar *cur;
8048 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00008049
Daniel Veillard03226812004-11-01 14:55:21 +00008050 cur = ctxt->cur;
8051
8052 c = CUR_CHAR(l);
8053 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8054 (!IS_LETTER(c) && (c != '_') &&
8055 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008056 return(NULL);
8057 }
8058
Daniel Veillard03226812004-11-01 14:55:21 +00008059 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8060 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8061 (c == '.') || (c == '-') ||
8062 (c == '_') || (c == ':') ||
8063 (IS_COMBINING(c)) ||
8064 (IS_EXTENDER(c)))) {
8065 len += l;
8066 NEXTL(l);
8067 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +00008068 }
Daniel Veillard03226812004-11-01 14:55:21 +00008069 ret = xmlStrndup(cur, ctxt->cur - cur);
8070 ctxt->cur = cur;
8071 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00008072}
8073
8074/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008075 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008076 * @ctxt: the XPath Parser context
8077 *
8078 * [19] PathExpr ::= LocationPath
8079 * | FilterExpr
8080 * | FilterExpr '/' RelativeLocationPath
8081 * | FilterExpr '//' RelativeLocationPath
8082 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008083 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008084 * The / operator and // operators combine an arbitrary expression
8085 * and a relative location path. It is an error if the expression
8086 * does not evaluate to a node-set.
8087 * The / operator does composition in the same way as when / is
8088 * used in a location path. As in location paths, // is short for
8089 * /descendant-or-self::node()/.
8090 */
8091
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008092static void
8093xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008094 int lc = 1; /* Should we branch to LocationPath ? */
8095 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8096
8097 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008098 if ((CUR == '$') || (CUR == '(') ||
8099 (IS_ASCII_DIGIT(CUR)) ||
8100 (CUR == '\'') || (CUR == '"') ||
8101 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008102 lc = 0;
8103 } else if (CUR == '*') {
8104 /* relative or absolute location path */
8105 lc = 1;
8106 } else if (CUR == '/') {
8107 /* relative or absolute location path */
8108 lc = 1;
8109 } else if (CUR == '@') {
8110 /* relative abbreviated attribute location path */
8111 lc = 1;
8112 } else if (CUR == '.') {
8113 /* relative abbreviated attribute location path */
8114 lc = 1;
8115 } else {
8116 /*
8117 * Problem is finding if we have a name here whether it's:
8118 * - a nodetype
8119 * - a function call in which case it's followed by '('
8120 * - an axis in which case it's followed by ':'
8121 * - a element name
8122 * We do an a priori analysis here rather than having to
8123 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008124 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008125 * read/write/debug.
8126 */
8127 SKIP_BLANKS;
8128 name = xmlXPathScanName(ctxt);
8129 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8130#ifdef DEBUG_STEP
8131 xmlGenericError(xmlGenericErrorContext,
8132 "PathExpr: Axis\n");
8133#endif
8134 lc = 1;
8135 xmlFree(name);
8136 } else if (name != NULL) {
8137 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008138
8139
8140 while (NXT(len) != 0) {
8141 if (NXT(len) == '/') {
8142 /* element name */
8143#ifdef DEBUG_STEP
8144 xmlGenericError(xmlGenericErrorContext,
8145 "PathExpr: AbbrRelLocation\n");
8146#endif
8147 lc = 1;
8148 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008149 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008150 /* ignore blanks */
8151 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008152 } else if (NXT(len) == ':') {
8153#ifdef DEBUG_STEP
8154 xmlGenericError(xmlGenericErrorContext,
8155 "PathExpr: AbbrRelLocation\n");
8156#endif
8157 lc = 1;
8158 break;
8159 } else if ((NXT(len) == '(')) {
8160 /* Note Type or Function */
8161 if (xmlXPathIsNodeType(name)) {
8162#ifdef DEBUG_STEP
8163 xmlGenericError(xmlGenericErrorContext,
8164 "PathExpr: Type search\n");
8165#endif
8166 lc = 1;
8167 } else {
8168#ifdef DEBUG_STEP
8169 xmlGenericError(xmlGenericErrorContext,
8170 "PathExpr: function call\n");
8171#endif
8172 lc = 0;
8173 }
8174 break;
8175 } else if ((NXT(len) == '[')) {
8176 /* element name */
8177#ifdef DEBUG_STEP
8178 xmlGenericError(xmlGenericErrorContext,
8179 "PathExpr: AbbrRelLocation\n");
8180#endif
8181 lc = 1;
8182 break;
8183 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8184 (NXT(len) == '=')) {
8185 lc = 1;
8186 break;
8187 } else {
8188 lc = 1;
8189 break;
8190 }
8191 len++;
8192 }
8193 if (NXT(len) == 0) {
8194#ifdef DEBUG_STEP
8195 xmlGenericError(xmlGenericErrorContext,
8196 "PathExpr: AbbrRelLocation\n");
8197#endif
8198 /* element name */
8199 lc = 1;
8200 }
8201 xmlFree(name);
8202 } else {
William M. Brack08171912003-12-29 02:52:11 +00008203 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008204 XP_ERROR(XPATH_EXPR_ERROR);
8205 }
8206 }
8207
8208 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008209 if (CUR == '/') {
8210 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8211 } else {
8212 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008213 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008214 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008215 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008216 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008217 CHECK_ERROR;
8218 if ((CUR == '/') && (NXT(1) == '/')) {
8219 SKIP(2);
8220 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008221
8222 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8223 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8224 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8225
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008226 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008227 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008228 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008229 }
8230 }
8231 SKIP_BLANKS;
8232}
8233
8234/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008235 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008236 * @ctxt: the XPath Parser context
8237 *
8238 * [18] UnionExpr ::= PathExpr
8239 * | UnionExpr '|' PathExpr
8240 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008241 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008242 */
8243
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008244static void
8245xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8246 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008247 CHECK_ERROR;
8248 SKIP_BLANKS;
8249 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008250 int op1 = ctxt->comp->last;
8251 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008252
8253 NEXT;
8254 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008255 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008256
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008257 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8258
Owen Taylor3473f882001-02-23 17:55:21 +00008259 SKIP_BLANKS;
8260 }
Owen Taylor3473f882001-02-23 17:55:21 +00008261}
8262
8263/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008264 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008265 * @ctxt: the XPath Parser context
8266 *
8267 * [27] UnaryExpr ::= UnionExpr
8268 * | '-' UnaryExpr
8269 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008270 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008271 */
8272
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008273static void
8274xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008275 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008276 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008277
8278 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008279 while (CUR == '-') {
8280 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008281 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008282 NEXT;
8283 SKIP_BLANKS;
8284 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008285
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008286 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008287 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008288 if (found) {
8289 if (minus)
8290 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8291 else
8292 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008293 }
8294}
8295
8296/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008297 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008298 * @ctxt: the XPath Parser context
8299 *
8300 * [26] MultiplicativeExpr ::= UnaryExpr
8301 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8302 * | MultiplicativeExpr 'div' UnaryExpr
8303 * | MultiplicativeExpr 'mod' UnaryExpr
8304 * [34] MultiplyOperator ::= '*'
8305 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008306 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008307 */
8308
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008309static void
8310xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8311 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008312 CHECK_ERROR;
8313 SKIP_BLANKS;
8314 while ((CUR == '*') ||
8315 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8316 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8317 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008318 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008319
8320 if (CUR == '*') {
8321 op = 0;
8322 NEXT;
8323 } else if (CUR == 'd') {
8324 op = 1;
8325 SKIP(3);
8326 } else if (CUR == 'm') {
8327 op = 2;
8328 SKIP(3);
8329 }
8330 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008331 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008332 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008333 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008334 SKIP_BLANKS;
8335 }
8336}
8337
8338/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008339 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008340 * @ctxt: the XPath Parser context
8341 *
8342 * [25] AdditiveExpr ::= MultiplicativeExpr
8343 * | AdditiveExpr '+' MultiplicativeExpr
8344 * | AdditiveExpr '-' MultiplicativeExpr
8345 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008346 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008347 */
8348
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008349static void
8350xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008351
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008352 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008353 CHECK_ERROR;
8354 SKIP_BLANKS;
8355 while ((CUR == '+') || (CUR == '-')) {
8356 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008357 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008358
8359 if (CUR == '+') plus = 1;
8360 else plus = 0;
8361 NEXT;
8362 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008363 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008364 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008365 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008366 SKIP_BLANKS;
8367 }
8368}
8369
8370/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008371 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008372 * @ctxt: the XPath Parser context
8373 *
8374 * [24] RelationalExpr ::= AdditiveExpr
8375 * | RelationalExpr '<' AdditiveExpr
8376 * | RelationalExpr '>' AdditiveExpr
8377 * | RelationalExpr '<=' AdditiveExpr
8378 * | RelationalExpr '>=' AdditiveExpr
8379 *
8380 * A <= B > C is allowed ? Answer from James, yes with
8381 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8382 * which is basically what got implemented.
8383 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008384 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008385 * on the stack
8386 */
8387
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008388static void
8389xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8390 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008391 CHECK_ERROR;
8392 SKIP_BLANKS;
8393 while ((CUR == '<') ||
8394 (CUR == '>') ||
8395 ((CUR == '<') && (NXT(1) == '=')) ||
8396 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008397 int inf, strict;
8398 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008399
8400 if (CUR == '<') inf = 1;
8401 else inf = 0;
8402 if (NXT(1) == '=') strict = 0;
8403 else strict = 1;
8404 NEXT;
8405 if (!strict) NEXT;
8406 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008407 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008408 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008409 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008410 SKIP_BLANKS;
8411 }
8412}
8413
8414/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008415 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008416 * @ctxt: the XPath Parser context
8417 *
8418 * [23] EqualityExpr ::= RelationalExpr
8419 * | EqualityExpr '=' RelationalExpr
8420 * | EqualityExpr '!=' RelationalExpr
8421 *
8422 * A != B != C is allowed ? Answer from James, yes with
8423 * (RelationalExpr = RelationalExpr) = RelationalExpr
8424 * (RelationalExpr != RelationalExpr) != RelationalExpr
8425 * which is basically what got implemented.
8426 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008427 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008428 *
8429 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008430static void
8431xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8432 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008433 CHECK_ERROR;
8434 SKIP_BLANKS;
8435 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008436 int eq;
8437 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008438
8439 if (CUR == '=') eq = 1;
8440 else eq = 0;
8441 NEXT;
8442 if (!eq) NEXT;
8443 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008444 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008445 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008446 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008447 SKIP_BLANKS;
8448 }
8449}
8450
8451/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008452 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008453 * @ctxt: the XPath Parser context
8454 *
8455 * [22] AndExpr ::= EqualityExpr
8456 * | AndExpr 'and' EqualityExpr
8457 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008458 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008459 *
8460 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008461static void
8462xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8463 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008464 CHECK_ERROR;
8465 SKIP_BLANKS;
8466 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008467 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008468 SKIP(3);
8469 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008470 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008471 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008472 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008473 SKIP_BLANKS;
8474 }
8475}
8476
8477/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008478 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008479 * @ctxt: the XPath Parser context
8480 *
8481 * [14] Expr ::= OrExpr
8482 * [21] OrExpr ::= AndExpr
8483 * | OrExpr 'or' AndExpr
8484 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008485 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008486 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008487static void
8488xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8489 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008490 CHECK_ERROR;
8491 SKIP_BLANKS;
8492 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008493 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008494 SKIP(2);
8495 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008496 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008497 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008498 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8499 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008500 SKIP_BLANKS;
8501 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008502 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8503 /* more ops could be optimized too */
8504 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8505 }
Owen Taylor3473f882001-02-23 17:55:21 +00008506}
8507
8508/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008509 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008510 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008511 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008512 *
8513 * [8] Predicate ::= '[' PredicateExpr ']'
8514 * [9] PredicateExpr ::= Expr
8515 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008516 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008517 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008518static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008519xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008520 int op1 = ctxt->comp->last;
8521
8522 SKIP_BLANKS;
8523 if (CUR != '[') {
8524 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8525 }
8526 NEXT;
8527 SKIP_BLANKS;
8528
8529 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008530 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008531 CHECK_ERROR;
8532
8533 if (CUR != ']') {
8534 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8535 }
8536
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008537 if (filter)
8538 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8539 else
8540 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008541
8542 NEXT;
8543 SKIP_BLANKS;
8544}
8545
8546/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008547 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008548 * @ctxt: the XPath Parser context
8549 * @test: pointer to a xmlXPathTestVal
8550 * @type: pointer to a xmlXPathTypeVal
8551 * @prefix: placeholder for a possible name prefix
8552 *
8553 * [7] NodeTest ::= NameTest
8554 * | NodeType '(' ')'
8555 * | 'processing-instruction' '(' Literal ')'
8556 *
8557 * [37] NameTest ::= '*'
8558 * | NCName ':' '*'
8559 * | QName
8560 * [38] NodeType ::= 'comment'
8561 * | 'text'
8562 * | 'processing-instruction'
8563 * | 'node'
8564 *
William M. Brack08171912003-12-29 02:52:11 +00008565 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00008566 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008567static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008568xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8569 xmlXPathTypeVal *type, const xmlChar **prefix,
8570 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008571 int blanks;
8572
8573 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8574 STRANGE;
8575 return(NULL);
8576 }
William M. Brack78637da2003-07-31 14:47:38 +00008577 *type = (xmlXPathTypeVal) 0;
8578 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008579 *prefix = NULL;
8580 SKIP_BLANKS;
8581
8582 if ((name == NULL) && (CUR == '*')) {
8583 /*
8584 * All elements
8585 */
8586 NEXT;
8587 *test = NODE_TEST_ALL;
8588 return(NULL);
8589 }
8590
8591 if (name == NULL)
8592 name = xmlXPathParseNCName(ctxt);
8593 if (name == NULL) {
8594 XP_ERROR0(XPATH_EXPR_ERROR);
8595 }
8596
William M. Brack76e95df2003-10-18 16:20:14 +00008597 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008598 SKIP_BLANKS;
8599 if (CUR == '(') {
8600 NEXT;
8601 /*
8602 * NodeType or PI search
8603 */
8604 if (xmlStrEqual(name, BAD_CAST "comment"))
8605 *type = NODE_TYPE_COMMENT;
8606 else if (xmlStrEqual(name, BAD_CAST "node"))
8607 *type = NODE_TYPE_NODE;
8608 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8609 *type = NODE_TYPE_PI;
8610 else if (xmlStrEqual(name, BAD_CAST "text"))
8611 *type = NODE_TYPE_TEXT;
8612 else {
8613 if (name != NULL)
8614 xmlFree(name);
8615 XP_ERROR0(XPATH_EXPR_ERROR);
8616 }
8617
8618 *test = NODE_TEST_TYPE;
8619
8620 SKIP_BLANKS;
8621 if (*type == NODE_TYPE_PI) {
8622 /*
8623 * Specific case: search a PI by name.
8624 */
Owen Taylor3473f882001-02-23 17:55:21 +00008625 if (name != NULL)
8626 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008627 name = NULL;
8628 if (CUR != ')') {
8629 name = xmlXPathParseLiteral(ctxt);
8630 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008631 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008632 SKIP_BLANKS;
8633 }
Owen Taylor3473f882001-02-23 17:55:21 +00008634 }
8635 if (CUR != ')') {
8636 if (name != NULL)
8637 xmlFree(name);
8638 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8639 }
8640 NEXT;
8641 return(name);
8642 }
8643 *test = NODE_TEST_NAME;
8644 if ((!blanks) && (CUR == ':')) {
8645 NEXT;
8646
8647 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008648 * Since currently the parser context don't have a
8649 * namespace list associated:
8650 * The namespace name for this prefix can be computed
8651 * only at evaluation time. The compilation is done
8652 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008653 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008654#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008655 *prefix = xmlXPathNsLookup(ctxt->context, name);
8656 if (name != NULL)
8657 xmlFree(name);
8658 if (*prefix == NULL) {
8659 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8660 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008661#else
8662 *prefix = name;
8663#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008664
8665 if (CUR == '*') {
8666 /*
8667 * All elements
8668 */
8669 NEXT;
8670 *test = NODE_TEST_ALL;
8671 return(NULL);
8672 }
8673
8674 name = xmlXPathParseNCName(ctxt);
8675 if (name == NULL) {
8676 XP_ERROR0(XPATH_EXPR_ERROR);
8677 }
8678 }
8679 return(name);
8680}
8681
8682/**
8683 * xmlXPathIsAxisName:
8684 * @name: a preparsed name token
8685 *
8686 * [6] AxisName ::= 'ancestor'
8687 * | 'ancestor-or-self'
8688 * | 'attribute'
8689 * | 'child'
8690 * | 'descendant'
8691 * | 'descendant-or-self'
8692 * | 'following'
8693 * | 'following-sibling'
8694 * | 'namespace'
8695 * | 'parent'
8696 * | 'preceding'
8697 * | 'preceding-sibling'
8698 * | 'self'
8699 *
8700 * Returns the axis or 0
8701 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008702static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008703xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008704 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008705 switch (name[0]) {
8706 case 'a':
8707 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8708 ret = AXIS_ANCESTOR;
8709 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8710 ret = AXIS_ANCESTOR_OR_SELF;
8711 if (xmlStrEqual(name, BAD_CAST "attribute"))
8712 ret = AXIS_ATTRIBUTE;
8713 break;
8714 case 'c':
8715 if (xmlStrEqual(name, BAD_CAST "child"))
8716 ret = AXIS_CHILD;
8717 break;
8718 case 'd':
8719 if (xmlStrEqual(name, BAD_CAST "descendant"))
8720 ret = AXIS_DESCENDANT;
8721 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8722 ret = AXIS_DESCENDANT_OR_SELF;
8723 break;
8724 case 'f':
8725 if (xmlStrEqual(name, BAD_CAST "following"))
8726 ret = AXIS_FOLLOWING;
8727 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8728 ret = AXIS_FOLLOWING_SIBLING;
8729 break;
8730 case 'n':
8731 if (xmlStrEqual(name, BAD_CAST "namespace"))
8732 ret = AXIS_NAMESPACE;
8733 break;
8734 case 'p':
8735 if (xmlStrEqual(name, BAD_CAST "parent"))
8736 ret = AXIS_PARENT;
8737 if (xmlStrEqual(name, BAD_CAST "preceding"))
8738 ret = AXIS_PRECEDING;
8739 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8740 ret = AXIS_PRECEDING_SIBLING;
8741 break;
8742 case 's':
8743 if (xmlStrEqual(name, BAD_CAST "self"))
8744 ret = AXIS_SELF;
8745 break;
8746 }
8747 return(ret);
8748}
8749
8750/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008751 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008752 * @ctxt: the XPath Parser context
8753 *
8754 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8755 * | AbbreviatedStep
8756 *
8757 * [12] AbbreviatedStep ::= '.' | '..'
8758 *
8759 * [5] AxisSpecifier ::= AxisName '::'
8760 * | AbbreviatedAxisSpecifier
8761 *
8762 * [13] AbbreviatedAxisSpecifier ::= '@'?
8763 *
8764 * Modified for XPtr range support as:
8765 *
8766 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8767 * | AbbreviatedStep
8768 * | 'range-to' '(' Expr ')' Predicate*
8769 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008770 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008771 * A location step of . is short for self::node(). This is
8772 * particularly useful in conjunction with //. For example, the
8773 * location path .//para is short for
8774 * self::node()/descendant-or-self::node()/child::para
8775 * and so will select all para descendant elements of the context
8776 * node.
8777 * Similarly, a location step of .. is short for parent::node().
8778 * For example, ../title is short for parent::node()/child::title
8779 * and so will select the title children of the parent of the context
8780 * node.
8781 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008782static void
8783xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008784#ifdef LIBXML_XPTR_ENABLED
8785 int rangeto = 0;
8786 int op2 = -1;
8787#endif
8788
Owen Taylor3473f882001-02-23 17:55:21 +00008789 SKIP_BLANKS;
8790 if ((CUR == '.') && (NXT(1) == '.')) {
8791 SKIP(2);
8792 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008793 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8794 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008795 } else if (CUR == '.') {
8796 NEXT;
8797 SKIP_BLANKS;
8798 } else {
8799 xmlChar *name = NULL;
8800 const xmlChar *prefix = NULL;
8801 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008802 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008803 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008804 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008805
8806 /*
8807 * The modification needed for XPointer change to the production
8808 */
8809#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008810 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008811 name = xmlXPathParseNCName(ctxt);
8812 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008813 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008814 xmlFree(name);
8815 SKIP_BLANKS;
8816 if (CUR != '(') {
8817 XP_ERROR(XPATH_EXPR_ERROR);
8818 }
8819 NEXT;
8820 SKIP_BLANKS;
8821
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008822 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008823 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008824 CHECK_ERROR;
8825
8826 SKIP_BLANKS;
8827 if (CUR != ')') {
8828 XP_ERROR(XPATH_EXPR_ERROR);
8829 }
8830 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008831 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008832 goto eval_predicates;
8833 }
8834 }
8835#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008836 if (CUR == '*') {
8837 axis = AXIS_CHILD;
8838 } else {
8839 if (name == NULL)
8840 name = xmlXPathParseNCName(ctxt);
8841 if (name != NULL) {
8842 axis = xmlXPathIsAxisName(name);
8843 if (axis != 0) {
8844 SKIP_BLANKS;
8845 if ((CUR == ':') && (NXT(1) == ':')) {
8846 SKIP(2);
8847 xmlFree(name);
8848 name = NULL;
8849 } else {
8850 /* an element name can conflict with an axis one :-\ */
8851 axis = AXIS_CHILD;
8852 }
Owen Taylor3473f882001-02-23 17:55:21 +00008853 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008854 axis = AXIS_CHILD;
8855 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008856 } else if (CUR == '@') {
8857 NEXT;
8858 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008859 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008860 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008861 }
Owen Taylor3473f882001-02-23 17:55:21 +00008862 }
8863
8864 CHECK_ERROR;
8865
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008866 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008867 if (test == 0)
8868 return;
8869
8870#ifdef DEBUG_STEP
8871 xmlGenericError(xmlGenericErrorContext,
8872 "Basis : computing new set\n");
8873#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008874
Owen Taylor3473f882001-02-23 17:55:21 +00008875#ifdef DEBUG_STEP
8876 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008877 if (ctxt->value == NULL)
8878 xmlGenericError(xmlGenericErrorContext, "no value\n");
8879 else if (ctxt->value->nodesetval == NULL)
8880 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8881 else
8882 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008883#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008884
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008885#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008886eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008887#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008888 op1 = ctxt->comp->last;
8889 ctxt->comp->last = -1;
8890
Owen Taylor3473f882001-02-23 17:55:21 +00008891 SKIP_BLANKS;
8892 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008893 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008894 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008895
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008896#ifdef LIBXML_XPTR_ENABLED
8897 if (rangeto) {
8898 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8899 } else
8900#endif
8901 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8902 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008903
Owen Taylor3473f882001-02-23 17:55:21 +00008904 }
8905#ifdef DEBUG_STEP
8906 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008907 if (ctxt->value == NULL)
8908 xmlGenericError(xmlGenericErrorContext, "no value\n");
8909 else if (ctxt->value->nodesetval == NULL)
8910 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8911 else
8912 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8913 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008914#endif
8915}
8916
8917/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008918 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008919 * @ctxt: the XPath Parser context
8920 *
8921 * [3] RelativeLocationPath ::= Step
8922 * | RelativeLocationPath '/' Step
8923 * | AbbreviatedRelativeLocationPath
8924 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8925 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008926 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008927 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008928static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008929xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008930(xmlXPathParserContextPtr ctxt) {
8931 SKIP_BLANKS;
8932 if ((CUR == '/') && (NXT(1) == '/')) {
8933 SKIP(2);
8934 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008935 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8936 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008937 } else if (CUR == '/') {
8938 NEXT;
8939 SKIP_BLANKS;
8940 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008941 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008942 SKIP_BLANKS;
8943 while (CUR == '/') {
8944 if ((CUR == '/') && (NXT(1) == '/')) {
8945 SKIP(2);
8946 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008947 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008948 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008949 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008950 } else if (CUR == '/') {
8951 NEXT;
8952 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008953 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008954 }
8955 SKIP_BLANKS;
8956 }
8957}
8958
8959/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008960 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008961 * @ctxt: the XPath Parser context
8962 *
8963 * [1] LocationPath ::= RelativeLocationPath
8964 * | AbsoluteLocationPath
8965 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8966 * | AbbreviatedAbsoluteLocationPath
8967 * [10] AbbreviatedAbsoluteLocationPath ::=
8968 * '//' RelativeLocationPath
8969 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008970 * Compile a location path
8971 *
Owen Taylor3473f882001-02-23 17:55:21 +00008972 * // is short for /descendant-or-self::node()/. For example,
8973 * //para is short for /descendant-or-self::node()/child::para and
8974 * so will select any para element in the document (even a para element
8975 * that is a document element will be selected by //para since the
8976 * document element node is a child of the root node); div//para is
8977 * short for div/descendant-or-self::node()/child::para and so will
8978 * select all para descendants of div children.
8979 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008980static void
8981xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008982 SKIP_BLANKS;
8983 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008984 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008985 } else {
8986 while (CUR == '/') {
8987 if ((CUR == '/') && (NXT(1) == '/')) {
8988 SKIP(2);
8989 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008990 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8991 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008992 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008993 } else if (CUR == '/') {
8994 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008995 SKIP_BLANKS;
8996 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +00008997 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00008998 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008999 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009000 }
9001 }
9002 }
9003}
9004
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009005/************************************************************************
9006 * *
9007 * XPath precompiled expression evaluation *
9008 * *
9009 ************************************************************************/
9010
Daniel Veillardf06307e2001-07-03 10:35:50 +00009011static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009012xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
9013
9014/**
9015 * xmlXPathNodeCollectAndTest:
9016 * @ctxt: the XPath Parser context
9017 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009018 * @first: pointer to the first element in document order
9019 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009020 *
9021 * This is the function implementing a step: based on the current list
9022 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009023 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009024 *
9025 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00009026 *
William M. Brack08171912003-12-29 02:52:11 +00009027 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009028 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009029static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009030xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009031 xmlXPathStepOpPtr op,
9032 xmlNodePtr * first, xmlNodePtr * last)
9033{
William M. Brack78637da2003-07-31 14:47:38 +00009034 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9035 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9036 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009037 const xmlChar *prefix = op->value4;
9038 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009039 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009040
9041#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009042 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009043#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009044 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009045 xmlNodeSetPtr ret, list;
9046 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009047 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00009048 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009049 xmlNodePtr cur = NULL;
9050 xmlXPathObjectPtr obj;
9051 xmlNodeSetPtr nodelist;
9052 xmlNodePtr tmp;
9053
Daniel Veillardf06307e2001-07-03 10:35:50 +00009054 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009055 obj = valuePop(ctxt);
9056 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009057 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009058 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009059 URI = xmlXPathNsLookup(ctxt->context, prefix);
9060 if (URI == NULL)
9061 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00009062 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009063#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009064 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009065#endif
9066 switch (axis) {
9067 case AXIS_ANCESTOR:
9068#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009069 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009070#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009071 first = NULL;
9072 next = xmlXPathNextAncestor;
9073 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009074 case AXIS_ANCESTOR_OR_SELF:
9075#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009076 xmlGenericError(xmlGenericErrorContext,
9077 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009078#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009079 first = NULL;
9080 next = xmlXPathNextAncestorOrSelf;
9081 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009082 case AXIS_ATTRIBUTE:
9083#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009084 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009085#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009086 first = NULL;
9087 last = NULL;
9088 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009089 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009090 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009091 case AXIS_CHILD:
9092#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009093 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009094#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009095 last = NULL;
9096 next = xmlXPathNextChild;
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_DESCENDANT:
9100#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009101 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009102#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009103 last = NULL;
9104 next = xmlXPathNextDescendant;
9105 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009106 case AXIS_DESCENDANT_OR_SELF:
9107#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009108 xmlGenericError(xmlGenericErrorContext,
9109 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009110#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009111 last = NULL;
9112 next = xmlXPathNextDescendantOrSelf;
9113 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009114 case AXIS_FOLLOWING:
9115#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009116 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009117#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009118 last = NULL;
9119 next = xmlXPathNextFollowing;
9120 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009121 case AXIS_FOLLOWING_SIBLING:
9122#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009123 xmlGenericError(xmlGenericErrorContext,
9124 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009125#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009126 last = NULL;
9127 next = xmlXPathNextFollowingSibling;
9128 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009129 case AXIS_NAMESPACE:
9130#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009131 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009132#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009133 first = NULL;
9134 last = NULL;
9135 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009136 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009137 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009138 case AXIS_PARENT:
9139#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009140 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009141#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009142 first = NULL;
9143 next = xmlXPathNextParent;
9144 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009145 case AXIS_PRECEDING:
9146#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009147 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009148#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009149 first = NULL;
9150 next = xmlXPathNextPrecedingInternal;
9151 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009152 case AXIS_PRECEDING_SIBLING:
9153#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009154 xmlGenericError(xmlGenericErrorContext,
9155 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009156#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009157 first = NULL;
9158 next = xmlXPathNextPrecedingSibling;
9159 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009160 case AXIS_SELF:
9161#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009162 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009163#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009164 first = NULL;
9165 last = NULL;
9166 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009167 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009168 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009169 }
9170 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009171 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009172
9173 nodelist = obj->nodesetval;
9174 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009175 xmlXPathFreeObject(obj);
9176 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9177 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009178 }
9179 addNode = xmlXPathNodeSetAddUnique;
9180 ret = NULL;
9181#ifdef DEBUG_STEP
9182 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009183 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009184 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009185 case NODE_TEST_NONE:
9186 xmlGenericError(xmlGenericErrorContext,
9187 " searching for none !!!\n");
9188 break;
9189 case NODE_TEST_TYPE:
9190 xmlGenericError(xmlGenericErrorContext,
9191 " searching for type %d\n", type);
9192 break;
9193 case NODE_TEST_PI:
9194 xmlGenericError(xmlGenericErrorContext,
9195 " searching for PI !!!\n");
9196 break;
9197 case NODE_TEST_ALL:
9198 xmlGenericError(xmlGenericErrorContext,
9199 " searching for *\n");
9200 break;
9201 case NODE_TEST_NS:
9202 xmlGenericError(xmlGenericErrorContext,
9203 " searching for namespace %s\n",
9204 prefix);
9205 break;
9206 case NODE_TEST_NAME:
9207 xmlGenericError(xmlGenericErrorContext,
9208 " searching for name %s\n", name);
9209 if (prefix != NULL)
9210 xmlGenericError(xmlGenericErrorContext,
9211 " with namespace %s\n", prefix);
9212 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009213 }
9214 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9215#endif
9216 /*
9217 * 2.3 Node Tests
9218 * - For the attribute axis, the principal node type is attribute.
9219 * - For the namespace axis, the principal node type is namespace.
9220 * - For other axes, the principal node type is element.
9221 *
9222 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009223 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009224 * select all element children of the context node
9225 */
9226 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009227 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009228 ctxt->context->node = nodelist->nodeTab[i];
9229
Daniel Veillardf06307e2001-07-03 10:35:50 +00009230 cur = NULL;
9231 list = xmlXPathNodeSetCreate(NULL);
9232 do {
9233 cur = next(ctxt, cur);
9234 if (cur == NULL)
9235 break;
9236 if ((first != NULL) && (*first == cur))
9237 break;
9238 if (((t % 256) == 0) &&
9239 (first != NULL) && (*first != NULL) &&
9240 (xmlXPathCmpNodes(*first, cur) >= 0))
9241 break;
9242 if ((last != NULL) && (*last == cur))
9243 break;
9244 if (((t % 256) == 0) &&
9245 (last != NULL) && (*last != NULL) &&
9246 (xmlXPathCmpNodes(cur, *last) >= 0))
9247 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009248 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009249#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009250 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9251#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009252 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009253 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009254 ctxt->context->node = tmp;
9255 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009256 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009257 if ((cur->type == type) ||
9258 ((type == NODE_TYPE_NODE) &&
9259 ((cur->type == XML_DOCUMENT_NODE) ||
9260 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9261 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009262 (cur->type == XML_NAMESPACE_DECL) ||
9263 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009264 (cur->type == XML_PI_NODE) ||
9265 (cur->type == XML_COMMENT_NODE) ||
9266 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009267 (cur->type == XML_TEXT_NODE))) ||
9268 ((type == NODE_TYPE_TEXT) &&
9269 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009270#ifdef DEBUG_STEP
9271 n++;
9272#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009273 addNode(list, cur);
9274 }
9275 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009276 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009277 if (cur->type == XML_PI_NODE) {
9278 if ((name != NULL) &&
9279 (!xmlStrEqual(name, cur->name)))
9280 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009281#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009282 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009283#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009284 addNode(list, cur);
9285 }
9286 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009287 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009288 if (axis == AXIS_ATTRIBUTE) {
9289 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009290#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009291 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009292#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009293 addNode(list, cur);
9294 }
9295 } else if (axis == AXIS_NAMESPACE) {
9296 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009297#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009298 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009299#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009300 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9301 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009302 }
9303 } else {
9304 if (cur->type == XML_ELEMENT_NODE) {
9305 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009306#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009307 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009308#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009309 addNode(list, cur);
9310 } else if ((cur->ns != NULL) &&
9311 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009312#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009313 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009314#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009315 addNode(list, cur);
9316 }
9317 }
9318 }
9319 break;
9320 case NODE_TEST_NS:{
9321 TODO;
9322 break;
9323 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009324 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009325 switch (cur->type) {
9326 case XML_ELEMENT_NODE:
9327 if (xmlStrEqual(name, cur->name)) {
9328 if (prefix == NULL) {
9329 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009330#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009331 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009332#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009333 addNode(list, cur);
9334 }
9335 } else {
9336 if ((cur->ns != NULL) &&
9337 (xmlStrEqual(URI,
9338 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009339#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009340 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009341#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009342 addNode(list, cur);
9343 }
9344 }
9345 }
9346 break;
9347 case XML_ATTRIBUTE_NODE:{
9348 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009349
Daniel Veillardf06307e2001-07-03 10:35:50 +00009350 if (xmlStrEqual(name, attr->name)) {
9351 if (prefix == NULL) {
9352 if ((attr->ns == NULL) ||
9353 (attr->ns->prefix == NULL)) {
9354#ifdef DEBUG_STEP
9355 n++;
9356#endif
9357 addNode(list,
9358 (xmlNodePtr) attr);
9359 }
9360 } else {
9361 if ((attr->ns != NULL) &&
9362 (xmlStrEqual(URI,
9363 attr->ns->
9364 href))) {
9365#ifdef DEBUG_STEP
9366 n++;
9367#endif
9368 addNode(list,
9369 (xmlNodePtr) attr);
9370 }
9371 }
9372 }
9373 break;
9374 }
9375 case XML_NAMESPACE_DECL:
9376 if (cur->type == XML_NAMESPACE_DECL) {
9377 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009378
Daniel Veillardf06307e2001-07-03 10:35:50 +00009379 if ((ns->prefix != NULL) && (name != NULL)
9380 && (xmlStrEqual(ns->prefix, name))) {
9381#ifdef DEBUG_STEP
9382 n++;
9383#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009384 xmlXPathNodeSetAddNs(list,
9385 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009386 }
9387 }
9388 break;
9389 default:
9390 break;
9391 }
9392 break;
9393 break;
9394 }
9395 } while (cur != NULL);
9396
9397 /*
9398 * If there is some predicate filtering do it now
9399 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009400 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009401 xmlXPathObjectPtr obj2;
9402
9403 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9404 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9405 CHECK_TYPE0(XPATH_NODESET);
9406 obj2 = valuePop(ctxt);
9407 list = obj2->nodesetval;
9408 obj2->nodesetval = NULL;
9409 xmlXPathFreeObject(obj2);
9410 }
9411 if (ret == NULL) {
9412 ret = list;
9413 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009414 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009415 xmlXPathFreeNodeSet(list);
9416 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009417 }
9418 ctxt->context->node = tmp;
9419#ifdef DEBUG_STEP
9420 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009421 "\nExamined %d nodes, found %d nodes at that step\n",
9422 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009423#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009424 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009425 if ((obj->boolval) && (obj->user != NULL)) {
9426 ctxt->value->boolval = 1;
9427 ctxt->value->user = obj->user;
9428 obj->user = NULL;
9429 obj->boolval = 0;
9430 }
9431 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009432 return(t);
9433}
9434
9435/**
9436 * xmlXPathNodeCollectAndTestNth:
9437 * @ctxt: the XPath Parser context
9438 * @op: the XPath precompiled step operation
9439 * @indx: the index to collect
9440 * @first: pointer to the first element in document order
9441 * @last: pointer to the last element in document order
9442 *
9443 * This is the function implementing a step: based on the current list
9444 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009445 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009446 *
9447 * Pushes the new NodeSet resulting from the search.
9448 * Returns the number of node traversed
9449 */
9450static int
9451xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9452 xmlXPathStepOpPtr op, int indx,
9453 xmlNodePtr * first, xmlNodePtr * last)
9454{
William M. Brack78637da2003-07-31 14:47:38 +00009455 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9456 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9457 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009458 const xmlChar *prefix = op->value4;
9459 const xmlChar *name = op->value5;
9460 const xmlChar *URI = NULL;
9461 int n = 0, t = 0;
9462
9463 int i;
9464 xmlNodeSetPtr list;
9465 xmlXPathTraversalFunction next = NULL;
9466 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9467 xmlNodePtr cur = NULL;
9468 xmlXPathObjectPtr obj;
9469 xmlNodeSetPtr nodelist;
9470 xmlNodePtr tmp;
9471
9472 CHECK_TYPE0(XPATH_NODESET);
9473 obj = valuePop(ctxt);
9474 addNode = xmlXPathNodeSetAdd;
9475 if (prefix != NULL) {
9476 URI = xmlXPathNsLookup(ctxt->context, prefix);
9477 if (URI == NULL)
9478 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9479 }
9480#ifdef DEBUG_STEP_NTH
9481 xmlGenericError(xmlGenericErrorContext, "new step : ");
9482 if (first != NULL) {
9483 if (*first != NULL)
9484 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9485 (*first)->name);
9486 else
9487 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9488 }
9489 if (last != NULL) {
9490 if (*last != NULL)
9491 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9492 (*last)->name);
9493 else
9494 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9495 }
9496#endif
9497 switch (axis) {
9498 case AXIS_ANCESTOR:
9499#ifdef DEBUG_STEP_NTH
9500 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9501#endif
9502 first = NULL;
9503 next = xmlXPathNextAncestor;
9504 break;
9505 case AXIS_ANCESTOR_OR_SELF:
9506#ifdef DEBUG_STEP_NTH
9507 xmlGenericError(xmlGenericErrorContext,
9508 "axis 'ancestors-or-self' ");
9509#endif
9510 first = NULL;
9511 next = xmlXPathNextAncestorOrSelf;
9512 break;
9513 case AXIS_ATTRIBUTE:
9514#ifdef DEBUG_STEP_NTH
9515 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9516#endif
9517 first = NULL;
9518 last = NULL;
9519 next = xmlXPathNextAttribute;
9520 break;
9521 case AXIS_CHILD:
9522#ifdef DEBUG_STEP_NTH
9523 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9524#endif
9525 last = NULL;
9526 next = xmlXPathNextChild;
9527 break;
9528 case AXIS_DESCENDANT:
9529#ifdef DEBUG_STEP_NTH
9530 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9531#endif
9532 last = NULL;
9533 next = xmlXPathNextDescendant;
9534 break;
9535 case AXIS_DESCENDANT_OR_SELF:
9536#ifdef DEBUG_STEP_NTH
9537 xmlGenericError(xmlGenericErrorContext,
9538 "axis 'descendant-or-self' ");
9539#endif
9540 last = NULL;
9541 next = xmlXPathNextDescendantOrSelf;
9542 break;
9543 case AXIS_FOLLOWING:
9544#ifdef DEBUG_STEP_NTH
9545 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9546#endif
9547 last = NULL;
9548 next = xmlXPathNextFollowing;
9549 break;
9550 case AXIS_FOLLOWING_SIBLING:
9551#ifdef DEBUG_STEP_NTH
9552 xmlGenericError(xmlGenericErrorContext,
9553 "axis 'following-siblings' ");
9554#endif
9555 last = NULL;
9556 next = xmlXPathNextFollowingSibling;
9557 break;
9558 case AXIS_NAMESPACE:
9559#ifdef DEBUG_STEP_NTH
9560 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9561#endif
9562 last = NULL;
9563 first = NULL;
9564 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9565 break;
9566 case AXIS_PARENT:
9567#ifdef DEBUG_STEP_NTH
9568 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9569#endif
9570 first = NULL;
9571 next = xmlXPathNextParent;
9572 break;
9573 case AXIS_PRECEDING:
9574#ifdef DEBUG_STEP_NTH
9575 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9576#endif
9577 first = NULL;
9578 next = xmlXPathNextPrecedingInternal;
9579 break;
9580 case AXIS_PRECEDING_SIBLING:
9581#ifdef DEBUG_STEP_NTH
9582 xmlGenericError(xmlGenericErrorContext,
9583 "axis 'preceding-sibling' ");
9584#endif
9585 first = NULL;
9586 next = xmlXPathNextPrecedingSibling;
9587 break;
9588 case AXIS_SELF:
9589#ifdef DEBUG_STEP_NTH
9590 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9591#endif
9592 first = NULL;
9593 last = NULL;
9594 next = xmlXPathNextSelf;
9595 break;
9596 }
9597 if (next == NULL)
9598 return(0);
9599
9600 nodelist = obj->nodesetval;
9601 if (nodelist == NULL) {
9602 xmlXPathFreeObject(obj);
9603 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9604 return(0);
9605 }
9606 addNode = xmlXPathNodeSetAddUnique;
9607#ifdef DEBUG_STEP_NTH
9608 xmlGenericError(xmlGenericErrorContext,
9609 " context contains %d nodes\n", nodelist->nodeNr);
9610 switch (test) {
9611 case NODE_TEST_NONE:
9612 xmlGenericError(xmlGenericErrorContext,
9613 " searching for none !!!\n");
9614 break;
9615 case NODE_TEST_TYPE:
9616 xmlGenericError(xmlGenericErrorContext,
9617 " searching for type %d\n", type);
9618 break;
9619 case NODE_TEST_PI:
9620 xmlGenericError(xmlGenericErrorContext,
9621 " searching for PI !!!\n");
9622 break;
9623 case NODE_TEST_ALL:
9624 xmlGenericError(xmlGenericErrorContext,
9625 " searching for *\n");
9626 break;
9627 case NODE_TEST_NS:
9628 xmlGenericError(xmlGenericErrorContext,
9629 " searching for namespace %s\n",
9630 prefix);
9631 break;
9632 case NODE_TEST_NAME:
9633 xmlGenericError(xmlGenericErrorContext,
9634 " searching for name %s\n", name);
9635 if (prefix != NULL)
9636 xmlGenericError(xmlGenericErrorContext,
9637 " with namespace %s\n", prefix);
9638 break;
9639 }
9640 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9641#endif
9642 /*
9643 * 2.3 Node Tests
9644 * - For the attribute axis, the principal node type is attribute.
9645 * - For the namespace axis, the principal node type is namespace.
9646 * - For other axes, the principal node type is element.
9647 *
9648 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009649 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009650 * select all element children of the context node
9651 */
9652 tmp = ctxt->context->node;
9653 list = xmlXPathNodeSetCreate(NULL);
9654 for (i = 0; i < nodelist->nodeNr; i++) {
9655 ctxt->context->node = nodelist->nodeTab[i];
9656
9657 cur = NULL;
9658 n = 0;
9659 do {
9660 cur = next(ctxt, cur);
9661 if (cur == NULL)
9662 break;
9663 if ((first != NULL) && (*first == cur))
9664 break;
9665 if (((t % 256) == 0) &&
9666 (first != NULL) && (*first != NULL) &&
9667 (xmlXPathCmpNodes(*first, cur) >= 0))
9668 break;
9669 if ((last != NULL) && (*last == cur))
9670 break;
9671 if (((t % 256) == 0) &&
9672 (last != NULL) && (*last != NULL) &&
9673 (xmlXPathCmpNodes(cur, *last) >= 0))
9674 break;
9675 t++;
9676 switch (test) {
9677 case NODE_TEST_NONE:
9678 ctxt->context->node = tmp;
9679 STRANGE return(0);
9680 case NODE_TEST_TYPE:
9681 if ((cur->type == type) ||
9682 ((type == NODE_TYPE_NODE) &&
9683 ((cur->type == XML_DOCUMENT_NODE) ||
9684 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9685 (cur->type == XML_ELEMENT_NODE) ||
9686 (cur->type == XML_PI_NODE) ||
9687 (cur->type == XML_COMMENT_NODE) ||
9688 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009689 (cur->type == XML_TEXT_NODE))) ||
9690 ((type == NODE_TYPE_TEXT) &&
9691 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009692 n++;
9693 if (n == indx)
9694 addNode(list, cur);
9695 }
9696 break;
9697 case NODE_TEST_PI:
9698 if (cur->type == XML_PI_NODE) {
9699 if ((name != NULL) &&
9700 (!xmlStrEqual(name, cur->name)))
9701 break;
9702 n++;
9703 if (n == indx)
9704 addNode(list, cur);
9705 }
9706 break;
9707 case NODE_TEST_ALL:
9708 if (axis == AXIS_ATTRIBUTE) {
9709 if (cur->type == XML_ATTRIBUTE_NODE) {
9710 n++;
9711 if (n == indx)
9712 addNode(list, cur);
9713 }
9714 } else if (axis == AXIS_NAMESPACE) {
9715 if (cur->type == XML_NAMESPACE_DECL) {
9716 n++;
9717 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009718 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9719 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009720 }
9721 } else {
9722 if (cur->type == XML_ELEMENT_NODE) {
9723 if (prefix == NULL) {
9724 n++;
9725 if (n == indx)
9726 addNode(list, cur);
9727 } else if ((cur->ns != NULL) &&
9728 (xmlStrEqual(URI, cur->ns->href))) {
9729 n++;
9730 if (n == indx)
9731 addNode(list, cur);
9732 }
9733 }
9734 }
9735 break;
9736 case NODE_TEST_NS:{
9737 TODO;
9738 break;
9739 }
9740 case NODE_TEST_NAME:
9741 switch (cur->type) {
9742 case XML_ELEMENT_NODE:
9743 if (xmlStrEqual(name, cur->name)) {
9744 if (prefix == NULL) {
9745 if (cur->ns == NULL) {
9746 n++;
9747 if (n == indx)
9748 addNode(list, cur);
9749 }
9750 } else {
9751 if ((cur->ns != NULL) &&
9752 (xmlStrEqual(URI,
9753 cur->ns->href))) {
9754 n++;
9755 if (n == indx)
9756 addNode(list, cur);
9757 }
9758 }
9759 }
9760 break;
9761 case XML_ATTRIBUTE_NODE:{
9762 xmlAttrPtr attr = (xmlAttrPtr) cur;
9763
9764 if (xmlStrEqual(name, attr->name)) {
9765 if (prefix == NULL) {
9766 if ((attr->ns == NULL) ||
9767 (attr->ns->prefix == NULL)) {
9768 n++;
9769 if (n == indx)
9770 addNode(list, cur);
9771 }
9772 } else {
9773 if ((attr->ns != NULL) &&
9774 (xmlStrEqual(URI,
9775 attr->ns->
9776 href))) {
9777 n++;
9778 if (n == indx)
9779 addNode(list, cur);
9780 }
9781 }
9782 }
9783 break;
9784 }
9785 case XML_NAMESPACE_DECL:
9786 if (cur->type == XML_NAMESPACE_DECL) {
9787 xmlNsPtr ns = (xmlNsPtr) cur;
9788
9789 if ((ns->prefix != NULL) && (name != NULL)
9790 && (xmlStrEqual(ns->prefix, name))) {
9791 n++;
9792 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009793 xmlXPathNodeSetAddNs(list,
9794 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009795 }
9796 }
9797 break;
9798 default:
9799 break;
9800 }
9801 break;
9802 break;
9803 }
9804 } while (n < indx);
9805 }
9806 ctxt->context->node = tmp;
9807#ifdef DEBUG_STEP_NTH
9808 xmlGenericError(xmlGenericErrorContext,
9809 "\nExamined %d nodes, found %d nodes at that step\n",
9810 t, list->nodeNr);
9811#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009812 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009813 if ((obj->boolval) && (obj->user != NULL)) {
9814 ctxt->value->boolval = 1;
9815 ctxt->value->user = obj->user;
9816 obj->user = NULL;
9817 obj->boolval = 0;
9818 }
9819 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009820 return(t);
9821}
9822
9823/**
9824 * xmlXPathCompOpEvalFirst:
9825 * @ctxt: the XPath parser context with the compiled expression
9826 * @op: an XPath compiled operation
9827 * @first: the first elem found so far
9828 *
9829 * Evaluate the Precompiled XPath operation searching only the first
9830 * element in document order
9831 *
9832 * Returns the number of examined objects.
9833 */
9834static int
9835xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9836 xmlXPathStepOpPtr op, xmlNodePtr * first)
9837{
9838 int total = 0, cur;
9839 xmlXPathCompExprPtr comp;
9840 xmlXPathObjectPtr arg1, arg2;
9841
Daniel Veillard556c6682001-10-06 09:59:51 +00009842 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009843 comp = ctxt->comp;
9844 switch (op->op) {
9845 case XPATH_OP_END:
9846 return (0);
9847 case XPATH_OP_UNION:
9848 total =
9849 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9850 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009851 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009852 if ((ctxt->value != NULL)
9853 && (ctxt->value->type == XPATH_NODESET)
9854 && (ctxt->value->nodesetval != NULL)
9855 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9856 /*
9857 * limit tree traversing to first node in the result
9858 */
9859 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9860 *first = ctxt->value->nodesetval->nodeTab[0];
9861 }
9862 cur =
9863 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9864 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009865 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009866 CHECK_TYPE0(XPATH_NODESET);
9867 arg2 = valuePop(ctxt);
9868
9869 CHECK_TYPE0(XPATH_NODESET);
9870 arg1 = valuePop(ctxt);
9871
9872 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9873 arg2->nodesetval);
9874 valuePush(ctxt, arg1);
9875 xmlXPathFreeObject(arg2);
9876 /* optimizer */
9877 if (total > cur)
9878 xmlXPathCompSwap(op);
9879 return (total + cur);
9880 case XPATH_OP_ROOT:
9881 xmlXPathRoot(ctxt);
9882 return (0);
9883 case XPATH_OP_NODE:
9884 if (op->ch1 != -1)
9885 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009886 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009887 if (op->ch2 != -1)
9888 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009889 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009890 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9891 return (total);
9892 case XPATH_OP_RESET:
9893 if (op->ch1 != -1)
9894 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009895 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009896 if (op->ch2 != -1)
9897 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009898 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009899 ctxt->context->node = NULL;
9900 return (total);
9901 case XPATH_OP_COLLECT:{
9902 if (op->ch1 == -1)
9903 return (total);
9904
9905 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009906 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009907
9908 /*
9909 * Optimization for [n] selection where n is a number
9910 */
9911 if ((op->ch2 != -1) &&
9912 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9913 (comp->steps[op->ch2].ch1 == -1) &&
9914 (comp->steps[op->ch2].ch2 != -1) &&
9915 (comp->steps[comp->steps[op->ch2].ch2].op ==
9916 XPATH_OP_VALUE)) {
9917 xmlXPathObjectPtr val;
9918
9919 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9920 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9921 int indx = (int) val->floatval;
9922
9923 if (val->floatval == (float) indx) {
9924 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9925 first, NULL);
9926 return (total);
9927 }
9928 }
9929 }
9930 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9931 return (total);
9932 }
9933 case XPATH_OP_VALUE:
9934 valuePush(ctxt,
9935 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9936 return (0);
9937 case XPATH_OP_SORT:
9938 if (op->ch1 != -1)
9939 total +=
9940 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9941 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009942 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009943 if ((ctxt->value != NULL)
9944 && (ctxt->value->type == XPATH_NODESET)
9945 && (ctxt->value->nodesetval != NULL))
9946 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9947 return (total);
9948 default:
9949 return (xmlXPathCompOpEval(ctxt, op));
9950 }
9951}
9952
9953/**
9954 * xmlXPathCompOpEvalLast:
9955 * @ctxt: the XPath parser context with the compiled expression
9956 * @op: an XPath compiled operation
9957 * @last: the last elem found so far
9958 *
9959 * Evaluate the Precompiled XPath operation searching only the last
9960 * element in document order
9961 *
William M. Brack08171912003-12-29 02:52:11 +00009962 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +00009963 */
9964static int
9965xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9966 xmlNodePtr * last)
9967{
9968 int total = 0, cur;
9969 xmlXPathCompExprPtr comp;
9970 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +00009971 xmlNodePtr bak;
9972 xmlDocPtr bakd;
9973 int pp;
9974 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009975
Daniel Veillard556c6682001-10-06 09:59:51 +00009976 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009977 comp = ctxt->comp;
9978 switch (op->op) {
9979 case XPATH_OP_END:
9980 return (0);
9981 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +00009982 bakd = ctxt->context->doc;
9983 bak = ctxt->context->node;
9984 pp = ctxt->context->proximityPosition;
9985 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009986 total =
9987 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009988 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009989 if ((ctxt->value != NULL)
9990 && (ctxt->value->type == XPATH_NODESET)
9991 && (ctxt->value->nodesetval != NULL)
9992 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9993 /*
9994 * limit tree traversing to first node in the result
9995 */
9996 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9997 *last =
9998 ctxt->value->nodesetval->nodeTab[ctxt->value->
9999 nodesetval->nodeNr -
10000 1];
10001 }
William M. Brackce4fc562004-01-22 02:47:18 +000010002 ctxt->context->doc = bakd;
10003 ctxt->context->node = bak;
10004 ctxt->context->proximityPosition = pp;
10005 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010006 cur =
10007 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010008 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010009 if ((ctxt->value != NULL)
10010 && (ctxt->value->type == XPATH_NODESET)
10011 && (ctxt->value->nodesetval != NULL)
10012 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10013 }
10014 CHECK_TYPE0(XPATH_NODESET);
10015 arg2 = valuePop(ctxt);
10016
10017 CHECK_TYPE0(XPATH_NODESET);
10018 arg1 = valuePop(ctxt);
10019
10020 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10021 arg2->nodesetval);
10022 valuePush(ctxt, arg1);
10023 xmlXPathFreeObject(arg2);
10024 /* optimizer */
10025 if (total > cur)
10026 xmlXPathCompSwap(op);
10027 return (total + cur);
10028 case XPATH_OP_ROOT:
10029 xmlXPathRoot(ctxt);
10030 return (0);
10031 case XPATH_OP_NODE:
10032 if (op->ch1 != -1)
10033 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010034 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010035 if (op->ch2 != -1)
10036 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010037 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010038 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10039 return (total);
10040 case XPATH_OP_RESET:
10041 if (op->ch1 != -1)
10042 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010043 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010044 if (op->ch2 != -1)
10045 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010046 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010047 ctxt->context->node = NULL;
10048 return (total);
10049 case XPATH_OP_COLLECT:{
10050 if (op->ch1 == -1)
10051 return (0);
10052
10053 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010054 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010055
10056 /*
10057 * Optimization for [n] selection where n is a number
10058 */
10059 if ((op->ch2 != -1) &&
10060 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10061 (comp->steps[op->ch2].ch1 == -1) &&
10062 (comp->steps[op->ch2].ch2 != -1) &&
10063 (comp->steps[comp->steps[op->ch2].ch2].op ==
10064 XPATH_OP_VALUE)) {
10065 xmlXPathObjectPtr val;
10066
10067 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10068 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10069 int indx = (int) val->floatval;
10070
10071 if (val->floatval == (float) indx) {
10072 total +=
10073 xmlXPathNodeCollectAndTestNth(ctxt, op,
10074 indx, NULL,
10075 last);
10076 return (total);
10077 }
10078 }
10079 }
10080 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10081 return (total);
10082 }
10083 case XPATH_OP_VALUE:
10084 valuePush(ctxt,
10085 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10086 return (0);
10087 case XPATH_OP_SORT:
10088 if (op->ch1 != -1)
10089 total +=
10090 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10091 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010092 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010093 if ((ctxt->value != NULL)
10094 && (ctxt->value->type == XPATH_NODESET)
10095 && (ctxt->value->nodesetval != NULL))
10096 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10097 return (total);
10098 default:
10099 return (xmlXPathCompOpEval(ctxt, op));
10100 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010101}
10102
Owen Taylor3473f882001-02-23 17:55:21 +000010103/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010104 * xmlXPathCompOpEval:
10105 * @ctxt: the XPath parser context with the compiled expression
10106 * @op: an XPath compiled operation
10107 *
10108 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010109 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010110 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010111static int
10112xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10113{
10114 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010115 int equal, ret;
10116 xmlXPathCompExprPtr comp;
10117 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010118 xmlNodePtr bak;
10119 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010120 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010121 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010122
Daniel Veillard556c6682001-10-06 09:59:51 +000010123 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010124 comp = ctxt->comp;
10125 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010126 case XPATH_OP_END:
10127 return (0);
10128 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010129 bakd = ctxt->context->doc;
10130 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010131 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010132 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010133 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010134 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010135 xmlXPathBooleanFunction(ctxt, 1);
10136 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10137 return (total);
10138 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010139 ctxt->context->doc = bakd;
10140 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010141 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010142 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010143 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010144 if (ctxt->error) {
10145 xmlXPathFreeObject(arg2);
10146 return(0);
10147 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010148 xmlXPathBooleanFunction(ctxt, 1);
10149 arg1 = valuePop(ctxt);
10150 arg1->boolval &= arg2->boolval;
10151 valuePush(ctxt, arg1);
10152 xmlXPathFreeObject(arg2);
10153 return (total);
10154 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010155 bakd = ctxt->context->doc;
10156 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010157 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010158 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010159 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010160 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010161 xmlXPathBooleanFunction(ctxt, 1);
10162 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10163 return (total);
10164 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010165 ctxt->context->doc = bakd;
10166 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010167 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010168 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010169 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010170 if (ctxt->error) {
10171 xmlXPathFreeObject(arg2);
10172 return(0);
10173 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010174 xmlXPathBooleanFunction(ctxt, 1);
10175 arg1 = valuePop(ctxt);
10176 arg1->boolval |= arg2->boolval;
10177 valuePush(ctxt, arg1);
10178 xmlXPathFreeObject(arg2);
10179 return (total);
10180 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010181 bakd = ctxt->context->doc;
10182 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010183 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010184 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010185 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010186 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010187 ctxt->context->doc = bakd;
10188 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010189 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010190 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010191 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010192 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010193 if (op->value)
10194 equal = xmlXPathEqualValues(ctxt);
10195 else
10196 equal = xmlXPathNotEqualValues(ctxt);
10197 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010198 return (total);
10199 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010200 bakd = ctxt->context->doc;
10201 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010202 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010203 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010204 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010205 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010206 ctxt->context->doc = bakd;
10207 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010208 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010209 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010210 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010211 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010212 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10213 valuePush(ctxt, xmlXPathNewBoolean(ret));
10214 return (total);
10215 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010216 bakd = ctxt->context->doc;
10217 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010218 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010219 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010220 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010221 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010222 if (op->ch2 != -1) {
10223 ctxt->context->doc = bakd;
10224 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010225 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010226 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010227 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010228 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010229 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010230 if (op->value == 0)
10231 xmlXPathSubValues(ctxt);
10232 else if (op->value == 1)
10233 xmlXPathAddValues(ctxt);
10234 else if (op->value == 2)
10235 xmlXPathValueFlipSign(ctxt);
10236 else if (op->value == 3) {
10237 CAST_TO_NUMBER;
10238 CHECK_TYPE0(XPATH_NUMBER);
10239 }
10240 return (total);
10241 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010242 bakd = ctxt->context->doc;
10243 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010244 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010245 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010246 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010247 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010248 ctxt->context->doc = bakd;
10249 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010250 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010251 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010252 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010253 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010254 if (op->value == 0)
10255 xmlXPathMultValues(ctxt);
10256 else if (op->value == 1)
10257 xmlXPathDivValues(ctxt);
10258 else if (op->value == 2)
10259 xmlXPathModValues(ctxt);
10260 return (total);
10261 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010262 bakd = ctxt->context->doc;
10263 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010264 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010265 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010266 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010267 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010268 ctxt->context->doc = bakd;
10269 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010270 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010271 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010272 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010273 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010274 CHECK_TYPE0(XPATH_NODESET);
10275 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010276
Daniel Veillardf06307e2001-07-03 10:35:50 +000010277 CHECK_TYPE0(XPATH_NODESET);
10278 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010279
Daniel Veillardf06307e2001-07-03 10:35:50 +000010280 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10281 arg2->nodesetval);
10282 valuePush(ctxt, arg1);
10283 xmlXPathFreeObject(arg2);
10284 return (total);
10285 case XPATH_OP_ROOT:
10286 xmlXPathRoot(ctxt);
10287 return (total);
10288 case XPATH_OP_NODE:
10289 if (op->ch1 != -1)
10290 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010291 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010292 if (op->ch2 != -1)
10293 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010294 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010295 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10296 return (total);
10297 case XPATH_OP_RESET:
10298 if (op->ch1 != -1)
10299 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010300 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010301 if (op->ch2 != -1)
10302 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010303 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010304 ctxt->context->node = NULL;
10305 return (total);
10306 case XPATH_OP_COLLECT:{
10307 if (op->ch1 == -1)
10308 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010309
Daniel Veillardf06307e2001-07-03 10:35:50 +000010310 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010311 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010312
Daniel Veillardf06307e2001-07-03 10:35:50 +000010313 /*
10314 * Optimization for [n] selection where n is a number
10315 */
10316 if ((op->ch2 != -1) &&
10317 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10318 (comp->steps[op->ch2].ch1 == -1) &&
10319 (comp->steps[op->ch2].ch2 != -1) &&
10320 (comp->steps[comp->steps[op->ch2].ch2].op ==
10321 XPATH_OP_VALUE)) {
10322 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010323
Daniel Veillardf06307e2001-07-03 10:35:50 +000010324 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10325 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10326 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010327
Daniel Veillardf06307e2001-07-03 10:35:50 +000010328 if (val->floatval == (float) indx) {
10329 total +=
10330 xmlXPathNodeCollectAndTestNth(ctxt, op,
10331 indx, NULL,
10332 NULL);
10333 return (total);
10334 }
10335 }
10336 }
10337 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10338 return (total);
10339 }
10340 case XPATH_OP_VALUE:
10341 valuePush(ctxt,
10342 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10343 return (total);
10344 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010345 xmlXPathObjectPtr val;
10346
Daniel Veillardf06307e2001-07-03 10:35:50 +000010347 if (op->ch1 != -1)
10348 total +=
10349 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010350 if (op->value5 == NULL) {
10351 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10352 if (val == NULL) {
10353 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10354 return(0);
10355 }
10356 valuePush(ctxt, val);
10357 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010358 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010359
Daniel Veillardf06307e2001-07-03 10:35:50 +000010360 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10361 if (URI == NULL) {
10362 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010363 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010364 op->value4, op->value5);
10365 return (total);
10366 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010367 val = xmlXPathVariableLookupNS(ctxt->context,
10368 op->value4, URI);
10369 if (val == NULL) {
10370 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10371 return(0);
10372 }
10373 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010374 }
10375 return (total);
10376 }
10377 case XPATH_OP_FUNCTION:{
10378 xmlXPathFunction func;
10379 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010380 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010381
10382 if (op->ch1 != -1)
10383 total +=
10384 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010385 if (ctxt->valueNr < op->value) {
10386 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010387 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010388 ctxt->error = XPATH_INVALID_OPERAND;
10389 return (total);
10390 }
10391 for (i = 0; i < op->value; i++)
10392 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10393 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010394 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010395 ctxt->error = XPATH_INVALID_OPERAND;
10396 return (total);
10397 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010398 if (op->cache != NULL)
10399 func = (xmlXPathFunction) op->cache;
10400 else {
10401 const xmlChar *URI = NULL;
10402
10403 if (op->value5 == NULL)
10404 func =
10405 xmlXPathFunctionLookup(ctxt->context,
10406 op->value4);
10407 else {
10408 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10409 if (URI == NULL) {
10410 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010411 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010412 op->value4, op->value5);
10413 return (total);
10414 }
10415 func = xmlXPathFunctionLookupNS(ctxt->context,
10416 op->value4, URI);
10417 }
10418 if (func == NULL) {
10419 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010420 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010421 op->value4);
10422 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010423 }
10424 op->cache = (void *) func;
10425 op->cacheURI = (void *) URI;
10426 }
10427 oldFunc = ctxt->context->function;
10428 oldFuncURI = ctxt->context->functionURI;
10429 ctxt->context->function = op->value4;
10430 ctxt->context->functionURI = op->cacheURI;
10431 func(ctxt, op->value);
10432 ctxt->context->function = oldFunc;
10433 ctxt->context->functionURI = oldFuncURI;
10434 return (total);
10435 }
10436 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010437 bakd = ctxt->context->doc;
10438 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010439 if (op->ch1 != -1)
10440 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010441 ctxt->context->doc = bakd;
10442 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010443 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010444 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010445 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010446 ctxt->context->doc = bakd;
10447 ctxt->context->node = bak;
10448 CHECK_ERROR0;
10449 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010450 return (total);
10451 case XPATH_OP_PREDICATE:
10452 case XPATH_OP_FILTER:{
10453 xmlXPathObjectPtr res;
10454 xmlXPathObjectPtr obj, tmp;
10455 xmlNodeSetPtr newset = NULL;
10456 xmlNodeSetPtr oldset;
10457 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000010458 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010459 int i;
10460
10461 /*
10462 * Optimization for ()[1] selection i.e. the first elem
10463 */
10464 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10465 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10466 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10467 xmlXPathObjectPtr val;
10468
10469 val = comp->steps[op->ch2].value4;
10470 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10471 (val->floatval == 1.0)) {
10472 xmlNodePtr first = NULL;
10473
10474 total +=
10475 xmlXPathCompOpEvalFirst(ctxt,
10476 &comp->steps[op->ch1],
10477 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010478 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010479 /*
10480 * The nodeset should be in document order,
10481 * Keep only the first value
10482 */
10483 if ((ctxt->value != NULL) &&
10484 (ctxt->value->type == XPATH_NODESET) &&
10485 (ctxt->value->nodesetval != NULL) &&
10486 (ctxt->value->nodesetval->nodeNr > 1))
10487 ctxt->value->nodesetval->nodeNr = 1;
10488 return (total);
10489 }
10490 }
10491 /*
10492 * Optimization for ()[last()] selection i.e. the last elem
10493 */
10494 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10495 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10496 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10497 int f = comp->steps[op->ch2].ch1;
10498
10499 if ((f != -1) &&
10500 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10501 (comp->steps[f].value5 == NULL) &&
10502 (comp->steps[f].value == 0) &&
10503 (comp->steps[f].value4 != NULL) &&
10504 (xmlStrEqual
10505 (comp->steps[f].value4, BAD_CAST "last"))) {
10506 xmlNodePtr last = NULL;
10507
10508 total +=
10509 xmlXPathCompOpEvalLast(ctxt,
10510 &comp->steps[op->ch1],
10511 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010512 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010513 /*
10514 * The nodeset should be in document order,
10515 * Keep only the last value
10516 */
10517 if ((ctxt->value != NULL) &&
10518 (ctxt->value->type == XPATH_NODESET) &&
10519 (ctxt->value->nodesetval != NULL) &&
10520 (ctxt->value->nodesetval->nodeTab != NULL) &&
10521 (ctxt->value->nodesetval->nodeNr > 1)) {
10522 ctxt->value->nodesetval->nodeTab[0] =
10523 ctxt->value->nodesetval->nodeTab[ctxt->
10524 value->
10525 nodesetval->
10526 nodeNr -
10527 1];
10528 ctxt->value->nodesetval->nodeNr = 1;
10529 }
10530 return (total);
10531 }
10532 }
10533
10534 if (op->ch1 != -1)
10535 total +=
10536 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010537 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010538 if (op->ch2 == -1)
10539 return (total);
10540 if (ctxt->value == NULL)
10541 return (total);
10542
10543 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010544
10545#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010546 /*
10547 * Hum are we filtering the result of an XPointer expression
10548 */
10549 if (ctxt->value->type == XPATH_LOCATIONSET) {
10550 xmlLocationSetPtr newlocset = NULL;
10551 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010552
Daniel Veillardf06307e2001-07-03 10:35:50 +000010553 /*
10554 * Extract the old locset, and then evaluate the result of the
10555 * expression for all the element in the locset. use it to grow
10556 * up a new locset.
10557 */
10558 CHECK_TYPE0(XPATH_LOCATIONSET);
10559 obj = valuePop(ctxt);
10560 oldlocset = obj->user;
10561 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010562
Daniel Veillardf06307e2001-07-03 10:35:50 +000010563 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10564 ctxt->context->contextSize = 0;
10565 ctxt->context->proximityPosition = 0;
10566 if (op->ch2 != -1)
10567 total +=
10568 xmlXPathCompOpEval(ctxt,
10569 &comp->steps[op->ch2]);
10570 res = valuePop(ctxt);
10571 if (res != NULL)
10572 xmlXPathFreeObject(res);
10573 valuePush(ctxt, obj);
10574 CHECK_ERROR0;
10575 return (total);
10576 }
10577 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010578
Daniel Veillardf06307e2001-07-03 10:35:50 +000010579 for (i = 0; i < oldlocset->locNr; i++) {
10580 /*
10581 * Run the evaluation with a node list made of a
10582 * single item in the nodelocset.
10583 */
10584 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010585 ctxt->context->contextSize = oldlocset->locNr;
10586 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010587 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10588 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010589
Daniel Veillardf06307e2001-07-03 10:35:50 +000010590 if (op->ch2 != -1)
10591 total +=
10592 xmlXPathCompOpEval(ctxt,
10593 &comp->steps[op->ch2]);
10594 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010595
Daniel Veillardf06307e2001-07-03 10:35:50 +000010596 /*
10597 * The result of the evaluation need to be tested to
10598 * decided whether the filter succeeded or not
10599 */
10600 res = valuePop(ctxt);
10601 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10602 xmlXPtrLocationSetAdd(newlocset,
10603 xmlXPathObjectCopy
10604 (oldlocset->locTab[i]));
10605 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010606
Daniel Veillardf06307e2001-07-03 10:35:50 +000010607 /*
10608 * Cleanup
10609 */
10610 if (res != NULL)
10611 xmlXPathFreeObject(res);
10612 if (ctxt->value == tmp) {
10613 res = valuePop(ctxt);
10614 xmlXPathFreeObject(res);
10615 }
10616
10617 ctxt->context->node = NULL;
10618 }
10619
10620 /*
10621 * The result is used as the new evaluation locset.
10622 */
10623 xmlXPathFreeObject(obj);
10624 ctxt->context->node = NULL;
10625 ctxt->context->contextSize = -1;
10626 ctxt->context->proximityPosition = -1;
10627 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10628 ctxt->context->node = oldnode;
10629 return (total);
10630 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010631#endif /* LIBXML_XPTR_ENABLED */
10632
Daniel Veillardf06307e2001-07-03 10:35:50 +000010633 /*
10634 * Extract the old set, and then evaluate the result of the
10635 * expression for all the element in the set. use it to grow
10636 * up a new set.
10637 */
10638 CHECK_TYPE0(XPATH_NODESET);
10639 obj = valuePop(ctxt);
10640 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010641
Daniel Veillardf06307e2001-07-03 10:35:50 +000010642 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000010643 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010644 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010645
Daniel Veillardf06307e2001-07-03 10:35:50 +000010646 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10647 ctxt->context->contextSize = 0;
10648 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000010649/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000010650 if (op->ch2 != -1)
10651 total +=
10652 xmlXPathCompOpEval(ctxt,
10653 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010654 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010655 res = valuePop(ctxt);
10656 if (res != NULL)
10657 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000010658*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000010659 valuePush(ctxt, obj);
10660 ctxt->context->node = oldnode;
10661 CHECK_ERROR0;
10662 } else {
10663 /*
10664 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000010665 * Also set the xpath document in case things like
10666 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000010667 */
10668 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010669
Daniel Veillardf06307e2001-07-03 10:35:50 +000010670 for (i = 0; i < oldset->nodeNr; i++) {
10671 /*
10672 * Run the evaluation with a node list made of
10673 * a single item in the nodeset.
10674 */
10675 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000010676 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
10677 (oldset->nodeTab[i]->doc != NULL))
10678 ctxt->context->doc = oldset->nodeTab[i]->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010679 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10680 valuePush(ctxt, tmp);
10681 ctxt->context->contextSize = oldset->nodeNr;
10682 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010683
Daniel Veillardf06307e2001-07-03 10:35:50 +000010684 if (op->ch2 != -1)
10685 total +=
10686 xmlXPathCompOpEval(ctxt,
10687 &comp->steps[op->ch2]);
10688 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010689
Daniel Veillardf06307e2001-07-03 10:35:50 +000010690 /*
William M. Brack08171912003-12-29 02:52:11 +000010691 * The result of the evaluation needs to be tested to
10692 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010693 */
10694 res = valuePop(ctxt);
10695 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10696 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10697 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010698
Daniel Veillardf06307e2001-07-03 10:35:50 +000010699 /*
10700 * Cleanup
10701 */
10702 if (res != NULL)
10703 xmlXPathFreeObject(res);
10704 if (ctxt->value == tmp) {
10705 res = valuePop(ctxt);
10706 xmlXPathFreeObject(res);
10707 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010708
Daniel Veillardf06307e2001-07-03 10:35:50 +000010709 ctxt->context->node = NULL;
10710 }
10711
10712 /*
10713 * The result is used as the new evaluation set.
10714 */
10715 xmlXPathFreeObject(obj);
10716 ctxt->context->node = NULL;
10717 ctxt->context->contextSize = -1;
10718 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000010719 /* may want to move this past the '}' later */
10720 ctxt->context->doc = oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010721 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10722 }
10723 ctxt->context->node = oldnode;
10724 return (total);
10725 }
10726 case XPATH_OP_SORT:
10727 if (op->ch1 != -1)
10728 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010729 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010730 if ((ctxt->value != NULL) &&
10731 (ctxt->value->type == XPATH_NODESET) &&
10732 (ctxt->value->nodesetval != NULL))
10733 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10734 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010735#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010736 case XPATH_OP_RANGETO:{
10737 xmlXPathObjectPtr range;
10738 xmlXPathObjectPtr res, obj;
10739 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010740 xmlLocationSetPtr newlocset = NULL;
10741 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010742 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000010743 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010744
Daniel Veillardf06307e2001-07-03 10:35:50 +000010745 if (op->ch1 != -1)
10746 total +=
10747 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10748 if (op->ch2 == -1)
10749 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010750
William M. Brack08171912003-12-29 02:52:11 +000010751 if (ctxt->value->type == XPATH_LOCATIONSET) {
10752 /*
10753 * Extract the old locset, and then evaluate the result of the
10754 * expression for all the element in the locset. use it to grow
10755 * up a new locset.
10756 */
10757 CHECK_TYPE0(XPATH_LOCATIONSET);
10758 obj = valuePop(ctxt);
10759 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010760
William M. Brack08171912003-12-29 02:52:11 +000010761 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000010762 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000010763 ctxt->context->contextSize = 0;
10764 ctxt->context->proximityPosition = 0;
10765 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10766 res = valuePop(ctxt);
10767 if (res != NULL)
10768 xmlXPathFreeObject(res);
10769 valuePush(ctxt, obj);
10770 CHECK_ERROR0;
10771 return (total);
10772 }
10773 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010774
William M. Brack08171912003-12-29 02:52:11 +000010775 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010776 /*
William M. Brack08171912003-12-29 02:52:11 +000010777 * Run the evaluation with a node list made of a
10778 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010779 */
William M. Brackf7eb7942003-12-31 07:59:17 +000010780 ctxt->context->node = oldlocset->locTab[i]->user;
10781 ctxt->context->contextSize = oldlocset->locNr;
10782 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010783 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10784 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010785
Daniel Veillardf06307e2001-07-03 10:35:50 +000010786 if (op->ch2 != -1)
10787 total +=
10788 xmlXPathCompOpEval(ctxt,
10789 &comp->steps[op->ch2]);
10790 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010791
Daniel Veillardf06307e2001-07-03 10:35:50 +000010792 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000010793 if (res->type == XPATH_LOCATIONSET) {
10794 xmlLocationSetPtr rloc =
10795 (xmlLocationSetPtr)res->user;
10796 for (j=0; j<rloc->locNr; j++) {
10797 range = xmlXPtrNewRange(
10798 oldlocset->locTab[i]->user,
10799 oldlocset->locTab[i]->index,
10800 rloc->locTab[j]->user2,
10801 rloc->locTab[j]->index2);
10802 if (range != NULL) {
10803 xmlXPtrLocationSetAdd(newlocset, range);
10804 }
10805 }
10806 } else {
10807 range = xmlXPtrNewRangeNodeObject(
10808 (xmlNodePtr)oldlocset->locTab[i]->user, res);
10809 if (range != NULL) {
10810 xmlXPtrLocationSetAdd(newlocset,range);
10811 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010812 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010813
Daniel Veillardf06307e2001-07-03 10:35:50 +000010814 /*
10815 * Cleanup
10816 */
10817 if (res != NULL)
10818 xmlXPathFreeObject(res);
10819 if (ctxt->value == tmp) {
10820 res = valuePop(ctxt);
10821 xmlXPathFreeObject(res);
10822 }
10823
10824 ctxt->context->node = NULL;
10825 }
William M. Brack72ee48d2003-12-30 08:30:19 +000010826 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000010827 CHECK_TYPE0(XPATH_NODESET);
10828 obj = valuePop(ctxt);
10829 oldset = obj->nodesetval;
10830 ctxt->context->node = NULL;
10831
10832 newlocset = xmlXPtrLocationSetCreate(NULL);
10833
10834 if (oldset != NULL) {
10835 for (i = 0; i < oldset->nodeNr; i++) {
10836 /*
10837 * Run the evaluation with a node list made of a single item
10838 * in the nodeset.
10839 */
10840 ctxt->context->node = oldset->nodeTab[i];
10841 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10842 valuePush(ctxt, tmp);
10843
10844 if (op->ch2 != -1)
10845 total +=
10846 xmlXPathCompOpEval(ctxt,
10847 &comp->steps[op->ch2]);
10848 CHECK_ERROR0;
10849
William M. Brack08171912003-12-29 02:52:11 +000010850 res = valuePop(ctxt);
10851 range =
10852 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10853 res);
10854 if (range != NULL) {
10855 xmlXPtrLocationSetAdd(newlocset, range);
10856 }
10857
10858 /*
10859 * Cleanup
10860 */
10861 if (res != NULL)
10862 xmlXPathFreeObject(res);
10863 if (ctxt->value == tmp) {
10864 res = valuePop(ctxt);
10865 xmlXPathFreeObject(res);
10866 }
10867
10868 ctxt->context->node = NULL;
10869 }
10870 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010871 }
10872
10873 /*
10874 * The result is used as the new evaluation set.
10875 */
10876 xmlXPathFreeObject(obj);
10877 ctxt->context->node = NULL;
10878 ctxt->context->contextSize = -1;
10879 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010880 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010881 return (total);
10882 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010883#endif /* LIBXML_XPTR_ENABLED */
10884 }
10885 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010886 "XPath: unknown precompiled operation %d\n", op->op);
10887 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010888}
10889
10890/**
10891 * xmlXPathRunEval:
10892 * @ctxt: the XPath parser context with the compiled expression
10893 *
10894 * Evaluate the Precompiled XPath expression in the given context.
10895 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010896static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010897xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10898 xmlXPathCompExprPtr comp;
10899
10900 if ((ctxt == NULL) || (ctxt->comp == NULL))
10901 return;
10902
10903 if (ctxt->valueTab == NULL) {
10904 /* Allocate the value stack */
10905 ctxt->valueTab = (xmlXPathObjectPtr *)
10906 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10907 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010908 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010909 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010910 }
10911 ctxt->valueNr = 0;
10912 ctxt->valueMax = 10;
10913 ctxt->value = NULL;
10914 }
10915 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010916 if(comp->last < 0) {
10917 xmlGenericError(xmlGenericErrorContext,
10918 "xmlXPathRunEval: last is less than zero\n");
10919 return;
10920 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010921 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10922}
10923
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010924/************************************************************************
10925 * *
10926 * Public interfaces *
10927 * *
10928 ************************************************************************/
10929
10930/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010931 * xmlXPathEvalPredicate:
10932 * @ctxt: the XPath context
10933 * @res: the Predicate Expression evaluation result
10934 *
10935 * Evaluate a predicate result for the current node.
10936 * A PredicateExpr is evaluated by evaluating the Expr and converting
10937 * the result to a boolean. If the result is a number, the result will
10938 * be converted to true if the number is equal to the position of the
10939 * context node in the context node list (as returned by the position
10940 * function) and will be converted to false otherwise; if the result
10941 * is not a number, then the result will be converted as if by a call
10942 * to the boolean function.
10943 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010944 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010945 */
10946int
10947xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000010948 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010949 switch (res->type) {
10950 case XPATH_BOOLEAN:
10951 return(res->boolval);
10952 case XPATH_NUMBER:
10953 return(res->floatval == ctxt->proximityPosition);
10954 case XPATH_NODESET:
10955 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010956 if (res->nodesetval == NULL)
10957 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010958 return(res->nodesetval->nodeNr != 0);
10959 case XPATH_STRING:
10960 return((res->stringval != NULL) &&
10961 (xmlStrlen(res->stringval) != 0));
10962 default:
10963 STRANGE
10964 }
10965 return(0);
10966}
10967
10968/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010969 * xmlXPathEvaluatePredicateResult:
10970 * @ctxt: the XPath Parser context
10971 * @res: the Predicate Expression evaluation result
10972 *
10973 * Evaluate a predicate result for the current node.
10974 * A PredicateExpr is evaluated by evaluating the Expr and converting
10975 * the result to a boolean. If the result is a number, the result will
10976 * be converted to true if the number is equal to the position of the
10977 * context node in the context node list (as returned by the position
10978 * function) and will be converted to false otherwise; if the result
10979 * is not a number, then the result will be converted as if by a call
10980 * to the boolean function.
10981 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010982 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010983 */
10984int
10985xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10986 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000010987 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010988 switch (res->type) {
10989 case XPATH_BOOLEAN:
10990 return(res->boolval);
10991 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000010992#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000010993 return((res->floatval == ctxt->context->proximityPosition) &&
10994 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000010995#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010996 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000010997#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010998 case XPATH_NODESET:
10999 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000011000 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000011001 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011002 return(res->nodesetval->nodeNr != 0);
11003 case XPATH_STRING:
11004 return((res->stringval != NULL) &&
11005 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000011006#ifdef LIBXML_XPTR_ENABLED
11007 case XPATH_LOCATIONSET:{
11008 xmlLocationSetPtr ptr = res->user;
11009 if (ptr == NULL)
11010 return(0);
11011 return (ptr->locNr != 0);
11012 }
11013#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011014 default:
11015 STRANGE
11016 }
11017 return(0);
11018}
11019
11020/**
Daniel Veillard4773df22004-01-23 13:15:13 +000011021 * xmlXPathCtxtCompile:
11022 * @ctxt: an XPath context
11023 * @str: the XPath expression
11024 *
11025 * Compile an XPath expression
11026 *
11027 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
11028 * the caller has to free the object.
11029 */
11030xmlXPathCompExprPtr
11031xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11032 xmlXPathParserContextPtr pctxt;
11033 xmlXPathCompExprPtr comp;
11034
11035 xmlXPathInit();
11036
11037 pctxt = xmlXPathNewParserContext(str, ctxt);
11038 xmlXPathCompileExpr(pctxt);
11039
11040 if( pctxt->error != XPATH_EXPRESSION_OK )
11041 {
11042 xmlXPathFreeParserContext(pctxt);
11043 return (0);
11044 }
11045
11046 if (*pctxt->cur != 0) {
11047 /*
11048 * aleksey: in some cases this line prints *second* error message
11049 * (see bug #78858) and probably this should be fixed.
11050 * However, we are not sure that all error messages are printed
11051 * out in other places. It's not critical so we leave it as-is for now
11052 */
11053 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11054 comp = NULL;
11055 } else {
11056 comp = pctxt->comp;
11057 pctxt->comp = NULL;
11058 }
11059 xmlXPathFreeParserContext(pctxt);
11060 if (comp != NULL) {
11061 comp->expr = xmlStrdup(str);
11062#ifdef DEBUG_EVAL_COUNTS
11063 comp->string = xmlStrdup(str);
11064 comp->nb = 0;
11065#endif
11066 }
11067 return(comp);
11068}
11069
11070/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011071 * xmlXPathCompile:
11072 * @str: the XPath expression
11073 *
11074 * Compile an XPath expression
11075 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000011076 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011077 * the caller has to free the object.
11078 */
11079xmlXPathCompExprPtr
11080xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000011081 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011082}
11083
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011084/**
11085 * xmlXPathCompiledEval:
11086 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000011087 * @ctx: the XPath context
11088 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011089 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000011090 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011091 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000011092 * the caller has to free the object.
11093 */
11094xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011095xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000011096 xmlXPathParserContextPtr ctxt;
11097 xmlXPathObjectPtr res, tmp, init = NULL;
11098 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000011099#ifndef LIBXML_THREAD_ENABLED
11100 static int reentance = 0;
11101#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011102
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011103 if ((comp == NULL) || (ctx == NULL))
11104 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011105 xmlXPathInit();
11106
11107 CHECK_CONTEXT(ctx)
11108
Daniel Veillard81463942001-10-16 12:34:39 +000011109#ifndef LIBXML_THREAD_ENABLED
11110 reentance++;
11111 if (reentance > 1)
11112 xmlXPathDisableOptimizer = 1;
11113#endif
11114
Daniel Veillardf06307e2001-07-03 10:35:50 +000011115#ifdef DEBUG_EVAL_COUNTS
11116 comp->nb++;
11117 if ((comp->string != NULL) && (comp->nb > 100)) {
11118 fprintf(stderr, "100 x %s\n", comp->string);
11119 comp->nb = 0;
11120 }
11121#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011122 ctxt = xmlXPathCompParserContext(comp, ctx);
11123 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011124
11125 if (ctxt->value == NULL) {
11126 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011127 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011128 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011129 } else {
11130 res = valuePop(ctxt);
11131 }
11132
Daniel Veillardf06307e2001-07-03 10:35:50 +000011133
Owen Taylor3473f882001-02-23 17:55:21 +000011134 do {
11135 tmp = valuePop(ctxt);
11136 if (tmp != NULL) {
11137 if (tmp != init)
11138 stack++;
11139 xmlXPathFreeObject(tmp);
11140 }
11141 } while (tmp != NULL);
11142 if ((stack != 0) && (res != NULL)) {
11143 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011144 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011145 stack);
11146 }
11147 if (ctxt->error != XPATH_EXPRESSION_OK) {
11148 xmlXPathFreeObject(res);
11149 res = NULL;
11150 }
11151
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011152
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011153 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011154 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011155#ifndef LIBXML_THREAD_ENABLED
11156 reentance--;
11157#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011158 return(res);
11159}
11160
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011161/**
11162 * xmlXPathEvalExpr:
11163 * @ctxt: the XPath Parser context
11164 *
11165 * Parse and evaluate an XPath expression in the given context,
11166 * then push the result on the context stack
11167 */
11168void
11169xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +000011170 if (ctxt == NULL) return;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011171 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011172 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011173 xmlXPathRunEval(ctxt);
11174}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011175
11176/**
11177 * xmlXPathEval:
11178 * @str: the XPath expression
11179 * @ctx: the XPath context
11180 *
11181 * Evaluate the XPath Location Path in the given context.
11182 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011183 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011184 * the caller has to free the object.
11185 */
11186xmlXPathObjectPtr
11187xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11188 xmlXPathParserContextPtr ctxt;
11189 xmlXPathObjectPtr res, tmp, init = NULL;
11190 int stack = 0;
11191
11192 xmlXPathInit();
11193
11194 CHECK_CONTEXT(ctx)
11195
11196 ctxt = xmlXPathNewParserContext(str, ctx);
11197 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011198
11199 if (ctxt->value == NULL) {
11200 xmlGenericError(xmlGenericErrorContext,
11201 "xmlXPathEval: evaluation failed\n");
11202 res = NULL;
11203 } else if (*ctxt->cur != 0) {
11204 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11205 res = NULL;
11206 } else {
11207 res = valuePop(ctxt);
11208 }
11209
11210 do {
11211 tmp = valuePop(ctxt);
11212 if (tmp != NULL) {
11213 if (tmp != init)
11214 stack++;
11215 xmlXPathFreeObject(tmp);
11216 }
11217 } while (tmp != NULL);
11218 if ((stack != 0) && (res != NULL)) {
11219 xmlGenericError(xmlGenericErrorContext,
11220 "xmlXPathEval: %d object left on the stack\n",
11221 stack);
11222 }
11223 if (ctxt->error != XPATH_EXPRESSION_OK) {
11224 xmlXPathFreeObject(res);
11225 res = NULL;
11226 }
11227
Owen Taylor3473f882001-02-23 17:55:21 +000011228 xmlXPathFreeParserContext(ctxt);
11229 return(res);
11230}
11231
11232/**
11233 * xmlXPathEvalExpression:
11234 * @str: the XPath expression
11235 * @ctxt: the XPath context
11236 *
11237 * Evaluate the XPath expression in the given context.
11238 *
11239 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11240 * the caller has to free the object.
11241 */
11242xmlXPathObjectPtr
11243xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11244 xmlXPathParserContextPtr pctxt;
11245 xmlXPathObjectPtr res, tmp;
11246 int stack = 0;
11247
11248 xmlXPathInit();
11249
11250 CHECK_CONTEXT(ctxt)
11251
11252 pctxt = xmlXPathNewParserContext(str, ctxt);
11253 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011254
11255 if (*pctxt->cur != 0) {
11256 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11257 res = NULL;
11258 } else {
11259 res = valuePop(pctxt);
11260 }
11261 do {
11262 tmp = valuePop(pctxt);
11263 if (tmp != NULL) {
11264 xmlXPathFreeObject(tmp);
11265 stack++;
11266 }
11267 } while (tmp != NULL);
11268 if ((stack != 0) && (res != NULL)) {
11269 xmlGenericError(xmlGenericErrorContext,
11270 "xmlXPathEvalExpression: %d object left on the stack\n",
11271 stack);
11272 }
11273 xmlXPathFreeParserContext(pctxt);
11274 return(res);
11275}
11276
Daniel Veillard42766c02002-08-22 20:52:17 +000011277/************************************************************************
11278 * *
11279 * Extra functions not pertaining to the XPath spec *
11280 * *
11281 ************************************************************************/
11282/**
11283 * xmlXPathEscapeUriFunction:
11284 * @ctxt: the XPath Parser context
11285 * @nargs: the number of arguments
11286 *
11287 * Implement the escape-uri() XPath function
11288 * string escape-uri(string $str, bool $escape-reserved)
11289 *
11290 * This function applies the URI escaping rules defined in section 2 of [RFC
11291 * 2396] to the string supplied as $uri-part, which typically represents all
11292 * or part of a URI. The effect of the function is to replace any special
11293 * character in the string by an escape sequence of the form %xx%yy...,
11294 * where xxyy... is the hexadecimal representation of the octets used to
11295 * represent the character in UTF-8.
11296 *
11297 * The set of characters that are escaped depends on the setting of the
11298 * boolean argument $escape-reserved.
11299 *
11300 * If $escape-reserved is true, all characters are escaped other than lower
11301 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11302 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11303 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11304 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11305 * A-F).
11306 *
11307 * If $escape-reserved is false, the behavior differs in that characters
11308 * referred to in [RFC 2396] as reserved characters are not escaped. These
11309 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11310 *
11311 * [RFC 2396] does not define whether escaped URIs should use lower case or
11312 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11313 * compared using string comparison functions, this function must always use
11314 * the upper-case letters A-F.
11315 *
11316 * Generally, $escape-reserved should be set to true when escaping a string
11317 * that is to form a single part of a URI, and to false when escaping an
11318 * entire URI or URI reference.
11319 *
11320 * In the case of non-ascii characters, the string is encoded according to
11321 * utf-8 and then converted according to RFC 2396.
11322 *
11323 * Examples
11324 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11325 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11326 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11327 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11328 *
11329 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011330static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011331xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11332 xmlXPathObjectPtr str;
11333 int escape_reserved;
11334 xmlBufferPtr target;
11335 xmlChar *cptr;
11336 xmlChar escape[4];
11337
11338 CHECK_ARITY(2);
11339
11340 escape_reserved = xmlXPathPopBoolean(ctxt);
11341
11342 CAST_TO_STRING;
11343 str = valuePop(ctxt);
11344
11345 target = xmlBufferCreate();
11346
11347 escape[0] = '%';
11348 escape[3] = 0;
11349
11350 if (target) {
11351 for (cptr = str->stringval; *cptr; cptr++) {
11352 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11353 (*cptr >= 'a' && *cptr <= 'z') ||
11354 (*cptr >= '0' && *cptr <= '9') ||
11355 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11356 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11357 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11358 (*cptr == '%' &&
11359 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11360 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11361 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11362 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11363 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11364 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11365 (!escape_reserved &&
11366 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11367 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11368 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11369 *cptr == ','))) {
11370 xmlBufferAdd(target, cptr, 1);
11371 } else {
11372 if ((*cptr >> 4) < 10)
11373 escape[1] = '0' + (*cptr >> 4);
11374 else
11375 escape[1] = 'A' - 10 + (*cptr >> 4);
11376 if ((*cptr & 0xF) < 10)
11377 escape[2] = '0' + (*cptr & 0xF);
11378 else
11379 escape[2] = 'A' - 10 + (*cptr & 0xF);
11380
11381 xmlBufferAdd(target, &escape[0], 3);
11382 }
11383 }
11384 }
11385 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11386 xmlBufferFree(target);
11387 xmlXPathFreeObject(str);
11388}
11389
Owen Taylor3473f882001-02-23 17:55:21 +000011390/**
11391 * xmlXPathRegisterAllFunctions:
11392 * @ctxt: the XPath context
11393 *
11394 * Registers all default XPath functions in this context
11395 */
11396void
11397xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11398{
11399 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11400 xmlXPathBooleanFunction);
11401 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11402 xmlXPathCeilingFunction);
11403 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11404 xmlXPathCountFunction);
11405 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11406 xmlXPathConcatFunction);
11407 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11408 xmlXPathContainsFunction);
11409 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11410 xmlXPathIdFunction);
11411 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11412 xmlXPathFalseFunction);
11413 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11414 xmlXPathFloorFunction);
11415 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11416 xmlXPathLastFunction);
11417 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11418 xmlXPathLangFunction);
11419 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11420 xmlXPathLocalNameFunction);
11421 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11422 xmlXPathNotFunction);
11423 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11424 xmlXPathNameFunction);
11425 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11426 xmlXPathNamespaceURIFunction);
11427 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11428 xmlXPathNormalizeFunction);
11429 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11430 xmlXPathNumberFunction);
11431 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11432 xmlXPathPositionFunction);
11433 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11434 xmlXPathRoundFunction);
11435 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11436 xmlXPathStringFunction);
11437 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11438 xmlXPathStringLengthFunction);
11439 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11440 xmlXPathStartsWithFunction);
11441 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11442 xmlXPathSubstringFunction);
11443 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11444 xmlXPathSubstringBeforeFunction);
11445 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11446 xmlXPathSubstringAfterFunction);
11447 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11448 xmlXPathSumFunction);
11449 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11450 xmlXPathTrueFunction);
11451 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11452 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011453
11454 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11455 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11456 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011457}
11458
11459#endif /* LIBXML_XPATH_ENABLED */